Tietorakenteet ja algoritmit Lineaariset perustietorakenteet Ari Korhonen 15.9.2015 Tietorakenteet ja algoritmit Y 1
2. TIETORAKENTEIDEN TOTEUTUS- PERIAATTEITA Peruskäsitteitä pieni kertaus ohjelmoinnin peruskäsitteistä taulukko linkitetty lista esimerkkejä (polynomin toteutus) abstraktit tietotyypit 15.9.2015 Tietorakenteet ja algoritmit Y 2
2.1 Peruskäsitteitä / Muuttujat Muuttujiin talletetaan dataa Muuttujiin liittyy tunnus, osoite ja tyyppi Muuttuja voi olla yksinkertainen tai rakenteinen Muuttujalla on jokin rooli ohjelman suorituksessa int count; /* count: askeltaja */ double sum; /* sum: kokooja */ Sortable table[1000]; /* table: järjestelijä */ Vakiot ovat arvoja, joita ei voi muuttaa final int SIZE = 100; (Java) #define SIZE 100 (C) SIZE = 100 (Python) 15.9.2015 Tietorakenteet ja algoritmit Y 3
2.1 Peruskäsitteitä / Muuttujat Alkeistyyppejä vai tietorakenteita? esim. Double-precision floating-point format (Wikipedia) esim. integer Pythonissa 1 struct _intblock { 2 struct _intblock *next; 3 PyIntObject objects[n_intobjects]; 4 }; 5 typedef struct _intblock PyIntBlock; 15.9.2015 Tietorakenteet ja algoritmit Y 4
2.1 Peruskäsitteitä / Muuttujat Datan lisäksi muuttuja voi sisältää myös osoitteen toiseen muuttujaan: double sum = 0; /* sum: kokooja */ double *p; /* p: askeltaja */ p = &table[0]; /* table: järjestelijä */ for (int i = 0; i < 1000; i++) { /* i: askeltaja */ sum += *p; p=p+1; } Sama kuin double sum = 0; /* sum: kokooja */ for (int i = 0; i < 1000; i++) /* i: askeltaja */ sum += table[i]; /* table: järjestelijä */ Tässä esimerkissä osoitinten käyttö tarpeetonta, mutta C-kielessä esim. merkkijonoja käsitellään usein osoittimien avulla. 15.9.2015 Tietorakenteet ja algoritmit Y 5
2.1 Peruskäsitteitä / Muuttujat Osoitinmuuttujien suurin merkitys on mahdollisuus luoda ja käsitellä dynaamisia tietorakenteita, esim. linkitettyjä listoja tai puita. Rakenteen solmut ovat muuttujia, joihin viitataan osoitinmuuttujien avulla. Solmuja voidaan luoda tarpeen mukaan ja niiden keskinäistä järjestystä voidaan vaihtaa. C-kielessä osoitinten käsittely on eksplisiittistä. Javassa ja Pythonissa rakenteet toteutetaan luokkien ja olioiden avulla. Luokka-tyyppinen muuttuja on itse asiassa osoitin muistissa olevaan olioon vrt. SortableKey x; vs. new SortableKey();! Tärkeä erikoistapaus on tyhjä osoitin NULL. 15.9.2015 Tietorakenteet ja algoritmit Y 6
2.1 Peruskäsitteitä / Tyypit Tyypit jaetaan alkeistyyppeihin ja rakenteisiin tyyppeihin Alkeistyyppejä ovat kokonaisluvut (int), reaaliluvut (double), merkkitieto (char) ja looginen tieto (boolean) Rakenteista tyyppiä olevat alkiot koostuvat alkeistyypeistä, esimerkiksi taulukot, tietueet, oliot Rakenteisten tyyppien alkiot voivat olla myös muita rakenteisia tyyppejä. Rakenteet voivat olla mielivaltaisen monimutkaisia ja monitasoisia. Taulukot ja tietueet ovat luonteeltaan staattisia tietorakenteita. Niiden koko on sidottu määrittelyyn On olemassa myös dynaamisia taulukoita Dynaamiset tietorakenteet luodaan osoitinmuuttujien avulla (C) tai oliorakenteina (Java, Python). 15.9.2015 Tietorakenteet ja algoritmit Y 7
2.1 Peruskäsitteitä / Ohjelman suoritus Ohjelman suorittamat toiminnot määritellään: Muuttujalle voidaan sijoittaa uusi arvo. Lausekkeissa lasketaan jokin arvo Lausekkeella voi olla myös sivuvaikutuksia muuttujien arvoihin Kontrollilauseet ohjaavat suoritusjärjestystä Ehtorakenteet (if - else, switch) Toistorakenteet (for, while-do, do-while) Isommat kokonaisuudet lasketaan usein funktioiden, proseduurien tai metodien avulla. Laskentaa ohjataan parametreilla. 15.9.2015 Tietorakenteet ja algoritmit Y 8
2.2 Yleistä tietorakenteista Tietorakenne voidaan luokitella kahdella tasolla Talletusrakenne on rakenne, joka sisältää joukon dataalkioita jollain tavalla talletettuna (esim. peräkkäin) ottamatta kantaa alkioiden sisältöön Esim. taulukko, linkitetty lista, binääripuu Abstrakti tietotyyppi (ADT) määrittelee tietotyypin, joilla on jokin semanttinen merkitys (tarvittavat operaatiot) Esim. hakemisto, prioriteettijono Abstraktit tietotyypit (määritellyt operaatiot) toteutetaan talletusrakenteiden avulla Esim. haetaan jokin alkio, jolla on tunniste (avain) tai lisätään tiettyä avainta vastaava alkio rakenteeseen 15.9.2015 Tietorakenteet ja algoritmit Y 9
2.2 Yleistä Tietorakenne on lineaarinen, jos kaikki sen alkiot on ryhmitetty peräkkäin. taulukko, linkitetty lista, pino, jono Tällaista rakennetta voidaan käyttää esim. yksinkertaisena hakurakenteena, tilapäisenä tallennusrakenteena. 15.9.2015 Tietorakenteet ja algoritmit Y 10
2.2 Yleistä Tietorakenne on staattinen, jos sille varattu muistitila on vakiokokoinen. Tietorakenne on dynaaminen, jos tietorakenteen koko tai muoto voi vaihdella. Mikä seuraavista on staattinen, mikä dynaaminen tietorakenne? Taulukko Tietue Dynaaminen taulukko Linkitetty lista Verkko Binääripuu Muistinvaraus kiinteä tai dynaaminen 15.9.2015 Tietorakenteet ja algoritmit Y 11
2.2 Yleistä Monet ohjelmointikielet tarjoavat valmiina joukon erilaisia tietorakenteita ja abstrakteja tietotyyppejä joko itse kielen rakenteina tai kirjastojen avulla toteutettuna C: Taulukko, dynaaminen taulukko Java: ArrayList, Map, HashMap, Python: Dictionary, List, Tuple, Monia asioita ei tarvitse toteuttaa itse, vaan voi käyttää valmiita kirjastoissa olevia toimintoja. On tärkeää ymmärtää, mitä tekee, koska erilaisia tietorakenteilla on erilaisia ominaisuuksia, jotka vaikuttavat suurestikin tehokkuuteen. 15.9.2015 Tietorakenteet ja algoritmit Y 12
2.2 Yleistä Alkion saavutettavuus talletusrakenteissa: Mitä eroa? Taulukko Tietue Linkitetty lista Binääripuu Verkko Alkion paikka voidaan laskea vakioajassa tai sitten ei. 15.9.2015 Tietorakenteet ja algoritmit Y 13
2.2 Yleistä Abstraktiotaso Mitä eroa? Binääripuu Jäsennyspuu 1 * + 3 2 A B C D G Binäärinen hakupuu Taulukko Hajautustaulukko Talletusrakenne vai semanttinen rakenne: Rakenne voi olla puhdas talletusrakenne tai abstrakti tietotyyppi, jolla on jokin semantiikka 15.9.2015 Tietorakenteet ja algoritmit Y 14
2.3 Taulukko Kuuluu yleisimpien ohjelmointikielten perusrakenteisiin Alkiot indeksoidaan ensimmäisestä viimeiseen. Mihin tahansa alkioon voidaan heti viitata. Taulukon alkioiden väliin ei voi lisätä uutta alkiota eikä sieltä voi poistaa alkiota. Rakenne on erittäin jäykkä, jos tällaisia toimintoja (päivityksiä) tarvitaan. Joissakin ohjelmointikielissä on taulukon tapaisia rakenteita, joissa näennäisesti voidaan tehdä asioita joustavasti, mutta tehokkuuden hinnalla (esim. Javan ArrayList)! 15.9.2015 Tietorakenteet ja algoritmit Y 15
Taulukko Taulukon määrittely C-kielessä: < type > < name >[<number of elements>] esim. int numbers[10]; numbers[5] = 1;! indeksointi alkaa nollasta (0 - N-1) Moniulotteiset taulukot Dynaaminen taulukko 15.9.2015 Tietorakenteet ja algoritmit Y 16
2.4 Linkitetyn listan (linked list) toteutus Lista toteutetaan tyypillisesti osoitinmuuttujien ja dynaamisen muistinvarauksen avulla. Voidaan toteuttaa myös pelkän taulukon avulla Tyypillinen määrittely C-kielessä: struct node { int data; struct node * next; }; typedef struct node * ListNode; ListNode p, q, r; Esimerkkilista: p 20 10 13 11 K2.1 q 15.9.2015 Tietorakenteet ja algoritmit Y 17 r
Eräs määrittelytapa Java-kielessä: class ListNode { int data; ListNode next; ListNode(int data) { this.data = data; this.next = null; } } ListNode p, q, r; Esim. p 20 10 13 11 q r 15.9.2015 Tietorakenteet ja algoritmit Y 18 K2.1
Alkion lisääminen on helppoa, kun käsillä on osoitin siihen alkioon, jonka jälkeen uusi alkio sijoitetaan p 20 10 13 11 (C) r = malloc(sizeof(node)); r->data = 99; r->next = q->next; q->next = r; (Java) r = new ListNode(99); r.next = q.next; q.next = r; q r 99 p 20 10 13 11 q r 99 15.9.2015 Tietorakenteet ja algoritmit Y 19
Alkion poistaminen käy helposti, kun on käsillä osoitin poistettavaa alkiota edeltävään alkioon: (C) (Java) r = q->next; q->next = r->next; free(r); r = q.next; q.next = r.next; p 20 10 13 11 K2.2 q r Miten poistaa ensimmäinen alkio? 15.9.2015 Tietorakenteet ja algoritmit Y 20
Header-alkion ansiosta myös ensimmäinen alkio voidaan poistaa samalla koodinpätkällä kuin muutkin. p head 20 10 13 11 K2.4 Samasta syystä (erikoistapausten välttäminen) toisinaan määritellään listan loppuun ylimääräinen alkio z, josta on viittaus itseensä (Sedgewick: Algorithms) p head 20 10 13 z Listan loppumisen tarkastaminen: K2.5 if (q == q->next)...; TAI if (q == z)... 15.9.2015 Tietorakenteet ja algoritmit Y 21
Esimerkkejä listan käsittelyfunktioiden toteuttamisesta (C): void print_list(listnode head) { ListNode list; /* list: kulkija */ } list = head->next; if (list == z) printf("list is empty\n"); else { while (list!= z) { printf("%d, list->data); list = list->next; } printf("\n"); } 15.9.2015 Tietorakenteet ja algoritmit Y 22
Lisää listan alkuun: void insert(listnode head, int key) { ListNode temp; /* temp: tilapäissäilö */ } temp = get_node(); // malloc temp->data = key; /* temp->data: kiintoarvo */ temp->next = head->next; /* temp->next: kiintoarvo */ head->next = temp; /* head->next: tuoreimman säilyttäjä */ 15.9.2015 Tietorakenteet ja algoritmit Y 23
Esimerkkejä listan käsittelyfunktioiden toteuttamisesta (Java): public void print_list(listnode head){ ListNode list; /* list: kulkija */ } list = head.next; if (list == z) System.out.println("List is empty"); else { while (list!= z) { System.out.print(list.data+" "); list = list.next; } System.out.println(); } 15.9.2015 Tietorakenteet ja algoritmit Y 24
class LinkedList { ListNode header; /* kiintoarvo */ ListNode z = new ListNode(null); /* kiintoarvo */ LinkedList () { header = new ListNode(null); header.next = z; /* tuoreimman säilyttäjä */ } } addfirst(int element) { ListNode temp; /* tilapäissäilö */ temp = new ListNode(element); temp.next = header.next; /* kiintoarvo */ header.next = temp; } 15.9.2015 Tietorakenteet ja algoritmit Y 25
Etsi alkio: ListNode search(listnode head, int key) { ListNode list; /* node: kulkija */ list = head->next; z->data = key; /* z->data: kiintoarvo, vartiosotilas */ while (list->data!= key) list = list->next; } return (list); 15.9.2015 Tietorakenteet ja algoritmit Y 26
boolean delete(listnode head, int key){ ListNode current, previous; z->data = key; /* z->data: kiintoarvo, vartiosotilas */ current = head->next; /* current: kulkija */ previous = head; /* previous: seuraaja, current->previous */ } while (current->data!= key) { previous = current; current = current->next; } if (current!= z) { previous->next = current->next; free (current); return (TRUE); } else return (FALSE); 15.9.2015 Tietorakenteet ja algoritmit Y 27
Lista voidaan toteuttaa myös 2 taulukon avulla (useampi lista voi käyttää samoja taulukoita) data[0..n] arvot next[0..n] osoittimet i data next 0 head 4 1 z 1 2 T 6 3 I 5 4 L 3 5 S 2 6 A 1 p h e a d L I S T A z 15.9.2015 Tietorakenteet ja algoritmit Y 28 K2.7
Kaksisuuntainen linkitetty lista on nopeampi käsitellä, mutta vaatii (vähän) enemmän muistitilaa. p E E S T A A S K2.8 struct node { char data; struct node *next, *previous; }; typedef struct node * DlistNode; 15.9.2015 Tietorakenteet ja algoritmit Y 29
Eräs määrittelytapa Python-kielessä: class ListNode: def init (self, value, previous=none, next=none): self.val = value self.next = next self.previous = previous 15.9.2015 Tietorakenteet ja algoritmit Y 30
Linkitetty lista (ilman header-alkiota) Kotitehtävä: toteuta vastaava luomalla erilliset head- ja z-oliot class LinkedList: def init (self): self.first = None self.last = None self.size = 0 def addfirst(self, item): self.size += 1 old = self.first self.first = ListNode(item, None, self.first) if old: old.previous = self.first if not self.last: self.last = self.first def addlast(self, item): 15.9.2015 Tietorakenteet ja algoritmit Y 31
Linkitetyn listan ominaisuudet Taulukkoa paljon joustavampi rakenne monessa tilanteessa. Lista koostuu yksittäisistä alkioista, joihin kuhunkin on talletettu dataa ja osoitin (referenssi) seuraavaan alkioon. Listan kokoa ei ole ennalta rajoitettu, vaan listaan voidaan lisätä ja siitä voidaan poistaa alkioita ajonaikaisesti. => Listan kokoa rajoittaa vain käytettävissä oleva muisti. Alkioita voi lisätä minne tahansa. Alkioita voi poistaa mistä tahansa. Alkioiden järjestystä voi vaihtaa. Listan alkiot voivat olla samaa tyyppiä tai lista voi olla geneerinen. 15.9.2015 Tietorakenteet ja algoritmit Y 32
LINKITETYN LISTAN TÄRKEIN RAJOITUS: Alkioita voi käydä läpi vain yksitellen, ts. alkioihin ei voi viitata suoraan (vrt. taulukko) Linkitetyn listan tärkeimmät operaatiot ovat: TULOSTUS HAKU LISÄYS POISTO PÄIVITYS TYHJÄN LISTAN LUOMINEN N:NNEN ALKION PALAUTTAMINEN ONKO LISTA TYHJÄ? 15.9.2015 Tietorakenteet ja algoritmit Y 33
Eri operaatioitten vaatima aika: TULOSTUS N HAKU N/2 (epäonnistunut: N) LISÄYS 1 POISTO N/2 Lista voidaan pitää järjestyksessä, jolloin (epäonnistunut) haku on nopeampi Tiedetään, ettei enää kannata etsiä, kun oikea kohta on jo ohitettu Lisäys on vastaavasti hitaampi (ei voidakaan lisätä aina listan alkuun) Listasta voidaan muodostaa rengas p 17 20 10 13 99 15.9.2015 Tietorakenteet ja algoritmit Y 34 K2.6
2.5 Tapausesimerkki POLYNOMI a i x i i=0...n Jos polynomi on tiheä l. suurin osa kertoimista poikkeaa nollasta => Esitetään kertoimet taulukossa #define MAX 1000 // magic number struct polynomi { int kerroin[max+1]; int asteluku; }; typedef struct polynomi Polynomi; 15.9.2015 Tietorakenteet ja algoritmit Y 35
Jos polynomi on harva (vähän termejä) => Esitetään kertoimet järjestettynä listana struct polynomi { int kerroin, eksponentti; struct polynomi * next; }; typedef struct polynomi * Polynomi; Ei rajaa polynomin asteluvulle! 15.9.2015 Tietorakenteet ja algoritmit Y 36
Toteutetaan polynomeille tulo-operaatio: Polynomi A_kertaa_B(Polynomi a,b) /* Toteutus riippuu valitusta tietorakenteesta */ } Tai Javalla rajapinta... public interface Polynomi { public Polynomi multiply(polynomi A); } => käsitellään polynomia abstraktiona!!! Kutsuvan ohjelman ei tarvitse tietää miten kertoimet on talletettu, toteutustapaa voidaan vaihtaa tarpeen mukaan!! 15.9.2015 Tietorakenteet ja algoritmit Y 37
2.6 Abstrakti tietotyyppi (abstract data type, ADT) Kun talletetulle tiedolle annetaan semanttinen merkitys (mitä tieto tarkoittaa) ja määritellään, mitä tiedolle saa tehdä (operaatiot), saadaan abstrakti tietotyyppi. Määritellään tietorakenteeseen kohdistuvat operaatiot Ei oteta kantaa, miten operaatiot toteutetaan Otetaan kantaa, mitä operaatiot tekevät (riittävä tarkkuustaso!) Mahdollistaa toteutuksen muuttamisen joustavasti Sama abstrakti tietotyyppi voidaan toteuttaa usean eri talletusrakenteen avulla. 15.9.2015 Tietorakenteet ja algoritmit Y 38
Abstraktit tietotyypit / Esimerkkejä A) Joukko abstraktina tietotyyppinä Määritellään vaikkapa operaatiot: - Leikkaus Set intersection(set A, Set B) - Unioni Set union(set A, Set B) ^ - Komplementti Set compl(set A, Set superset) - Koko (= alkioiden määrä) int size(set A) - Kuuluu joukkoon? boolean in(element E, Set A) Operaatiot toteutetaan aliohjelmina, metodeina, tms. Muualla ohjelmassa voidaan kutsua em. operaatioita tarvitsematta tietää, miten alkiot on talletettu (taulukko, lista, puu,...) 15.9.2015 Tietorakenteet ja algoritmit Y 39
B) Hakurakenne abstraktina tietotyyppinä Määritellään, että hakurakenne on kokoelma tietueita, jotka voidaan yksiselitteisesti tunnistaa niihin talletetun hakuavaimen arvon perusteella Määritellään esimerkiksi operaatiot Element Search(Key K) Element Insert(Key K, Data D) Element Delete(Key K) Element Next(Key K) [Previous] Etsi annettua tietuetta lähinnä seuraava [edellinen] tietue Element[] Range(Key From, Key To) Etsi tietueet, joiden avainarvot ovat avainarvojen [From,To] välissä 15.9.2015 Tietorakenteet ja algoritmit Y 40
C) Prioriteettijono abstraktina tietotyyppinä Määritellään, että rakenne on kokoelma alkioita, joihin jokaiseen liittyy alkion suhdetta muihin alkioihin kuvaava prioriteetti Määritellään esimerkiksi operaatiot Insert(Element E, int P) Lisää alkio ja aseta sen prioriteetiksi P Element DeleteMax() Poista ja palauta alkio, jonka prioriteettiarvo on suurin (tai deletemin - pienin) DecreaseKey(Element E, int delta) pienennä (tai IncreaseKey -suurenna) alkion prioriteettiä deltalla 15.9.2015 Tietorakenteet ja algoritmit Y 41
3. Lisää lineaarisista perustietorakenteista 3.1 Pino (stack) 3.2 Jono (queue) 3.3 Pakka (deque) 15.9.2015 Tietorakenteet ja algoritmit Y 42
3. Lineaariset perustietorakenteet Tietorakenne on lineaarinen, jos kaikki sen alkiot on ryhmitetty peräkkäin. Tällaista rakennetta voidaan käyttää esim. yksinkertaisena hakurakenteena, tilapäisenä tallennusrakenteena. Taulukko, lista Seuraavaksi tarkastellaan eräitä tärkeitä lineaarisia abstrakteja tietotyyppejä. 15.9.2015 Tietorakenteet ja algoritmit Y 43
3.1 Pino (stack) Toimii samaan tapaan kuin pöydällä oleva korttipakka Pino on abstrakti tietotyyppi, jolle on määritelty seuraavat operaatiot: Push(x) - lisää pinon päälle alkion x Pop() - palauttaa ja poistaa pinon päällimmäisen alkion Top() - palauttaa pinon päällimmäisen alkion (poistamatta sitä) IsEmpty() - palauttaa tiedon siitä, onko pino tyhjä 15.9.2015 Tietorakenteet ja algoritmit Y 44
Jonokuri LIFO (Last In - First Out) Kaikki pino-operaatiot voidaan toteuttaa vakioajassa (ei riipu pinon koosta) Pino voidaan implementoida taulukon avulla tai linkitettynä listana Toteutus taulukkona: apuna pino-osoitin (stack pointer), joka osoittaa päällimmäiseen alkioon... 7 isempty() (sp == -1) Taulukkototeutuksessa pinolle varattu tila voi loppua sp 6 5 4 3 2 1 0 K2.13 15.9.2015 Tietorakenteet ja algoritmit Y 45
Toteutus listana: top K2.14 push(): liitä uusi alkio listan alkuun pop(): poista ja palauta alkio listan alusta isempty(): tosi, jos lista on tyhjä top == null tai Header == Z (jos käytetään erillisiä head ja z--alkioita) 15.9.2015 Tietorakenteet ja algoritmit Y 46
Pinon sovelluksia Ohjelmointikielessä lausesulkujen tarkastus: kullekin alkusululle löytyy oikeantyyppinen loppusulku Kielessä voi esiintyä useita eri sulkutyyppejä, esim. C- kielessä (,); [,]; {,} Sulkuvirheet (esim. {(}) ) voivat usein sotkea kääntäjän toiminnan pahoin Syötevirran kääntäminen päinvastaiseen järjestykseen Ajonaikainen pino (aliohjelmakutsut): Kutsuvan ohjelman tila (=rekisterit) ja kutsun paikka (=program counter) pinoon Aliohjelmasta palattaessa voidaan palauttaa alkuperäinen tila 15.9.2015 Tietorakenteet ja algoritmit Y 47
Yksinkertainen lausesulkujen tarkastusperiaate Luetaan syötettä merkki kerrallaan Tutkitaan vain sulkumerkkejä Alkusulku asetetaan pinoon (push) Kohdattaessa loppusulku otetaan pinosta (pop) päällimmäinen sulku ü Jos pino on tyhjä (isempty) tai sulku on väärän tyyppinen virhe Algoritmin päättyessä pinon tulee olla tyhjä 15.9.2015 Tietorakenteet ja algoritmit Y 48
Lausekkeen arvon laskeminen Miten evaluoida lausekkeen arvo? Infix-notaatio: 5 * ( ( 9 + 8 ) * 4 * 6 + 7 ) Miten tallentaa välitulokset? Mikä on toimintajärjestys, kun lauseke luetaan ohjelmalle merkki merkiltä? 15.9.2015 Tietorakenteet ja algoritmit Y 49
Periaate: 1) Muunnetaan lauseke pinon avulla postfix-muotoon: 5 9 8 + 4 * 6 * 7 + * 2) Evaluoidaan postfix-lauseke pinon avulla 15.9.2015 Tietorakenteet ja algoritmit Y 50
INFIX-POSTFIX-muunnos pinon avulla Luetaan Infix-lauseketta merkki kerrallaan operandit [0-9]* tulostetaan suoraan ( asetetaan pinoon (PUSH) operaattorit *,+ otetaan pinosta (POP) ja tulostetaan operaattoreita, joilla on sama tai suurempi prioriteetti, sen jälkeen asetetaan viimeksi luettu operaattori pinoon. Sulkumerkkiä ( ei kuitenkaan lueta ) otetaan pinosta ja tulostetaan operaattoreita, kunnes löytyy alkusulku, joka myös luetaan, mutta ei tulosteta Kun syöte loppuu, otetaan pinosta ja tulostetaan loput operaattorit 15.9.2015 Tietorakenteet ja algoritmit Y 51
Esim. Muunnetaan lauseke 5*((9+8)*4*6+7) muotoon 598+4*6*7+* Syöte Pino Tuloste 5 5 * * ( *( ( *(( 9 9 + *((+ 8 8 ) *( + * *(* 4 4 * *(* * 6 6 + *(+ * 7 7 ) * + tyhjä * 15.9.2015 Tietorakenteet ja algoritmit Y 52
POSTFIX-lausekkeen arvo voidaan laskea pinon avulla Esim. lauseke 598+4*6*7+* Input Pino 5 5 9 5 9 8 5 9 8 + 5 17 4 5 17 4 * 5 68 6 5 68 6 * 5 408 7 5 408 7 + 5 415 * 2075 empty 15.9.2015 Tietorakenteet ja algoritmit Y 53
3.2 JONO (queue) Jono on abstrakti tietotyyppi, jolle on määritelty seuraavat operaatiot: Put(x) tai Enqueue(x) - lisää jonon loppuun alkion x Get() tai Dequeue() - palauttaa (ja poistaa) jonon ensimmäisen alkion First() - palauttaa jonon ensimmäisen alkion IsEmpty() - kertoo, onko jono tyhjä Jonokuri FIFO (First In First Out) Jono voidaan toteuttaa eri tavoin (taulukon avulla tai linkitettynä listana). Toteutetaan usein sirkulaarisena taulukkona (indeksit lasketaan modulo N). 15.9.2015 Tietorakenteet ja algoritmit Y 54
Jonon toteutus sirkulaarisena taulukkona l ast fi r st 0 1 2 3 4 5 6 7 MAX Jono[0.. MAX-1] put get first osoittaa jonon alkuun last osoittaa 1. vapaaseen paikkaan Jonossa yksi tyhjä paikka, jota ei käytetä 15.9.2015 Tietorakenteet ja algoritmit Y 55
Put(x): Jono[last] = x; /* Jono: säiliö */ last = (last+1) % MAX; /* last: askeltaja */ if (last == first) error; //Jono ei saa mennä täyteen! Get(): tmp = Jono[first]; /* tmp: tilapäissäilö */ first = (first+1) % MAX; /* first:askeltaja */ return tmp; First(): return Jono[first]; IsEmpty(): (last == first); 15.9.2015 Tietorakenteet ja algoritmit Y 56
Jonon toteutus listana struct node { datatype data; /* data: kiintoarvo; hyötykuorma */ struct node *next; /* next: kiintoarvo; seuraava alkio */ }; typedef struct node * Queue; fi r st l ast K2.16 15.9.2015 Tietorakenteet ja algoritmit Y 57
struct node *first, *last; /* first, last: kulkijat */ struct node *temp; /* tmp: tilapäissäilö */ Put(x): temp = (Queue)malloc(sizeof(struct node)); temp->data = x; temp->next = NULL; last->next = temp; last = temp; Get(): temp = first; x = first->data; first = first->next; free(temp) return (x); First(): return(first); IsEmpty(): return (first == NULL); 15.9.2015 Tietorakenteet ja algoritmit Y 58
Jonon sovelluksia Esim. Printterijono Puskuri tiedon välivarasto tietoa tulee tietoa lähtee tiedon järjestys säilyy Esim. tulostettava tiedosto menee puskurin kautta Diskreetti simulointi Esim. liikenne, tietoliikenne, palvelut Verkkoalgoritmit (esim. leveyssuuntainen haku eli BFS) 15.9.2015 Tietorakenteet ja algoritmit Y 59
3.3 PAKKA (deque) Alkioita voidaan asettaa rakenteen molempiin päihin, ja myös ottaa pois Vrt. korttipakka kädessä Määrittely jätetään kotitehtäväksi: Määrittele abstrakti tietotyyppi pakka 15.9.2015 Tietorakenteet ja algoritmit Y 60
Ensi kerraksi Tee viikkojen 37-39 viikkoharjoitukset Tutustu rekursion käsitteeseen Tutki esim. kalvosetin lopusta löytyviä Fibonacci- ja Hanoiesimerkkejä Piirrä itsenäisesti algoritmien rekursiohistoriapuut pienillä N:n arvoilla (esim. 4) 15.9.2015 Tietorakenteet ja algoritmit Y 61
Tietorakenteet ja algoritmit Algoritmit Ari Korhonen 15.9.2015 Tietorakenteet ja algoritmit Y 62
4.1 Algoritmit suhteessa tietorakenteisiin Useimmat algoritmit käsittelevät jotain tietorakennetta, eikä atomista dataa Käsiteltävä data on siten joukko data-alkioita, jotka muodostavat jonkin kokonaisuuden. Algoritmi käsittelee tätä kokonaisuutta eli tietorakennetta. Esimerkiksi: Lajitellaan tieto suuruusjärjestykseen Etsitään jotain yksittäistä tietoa suuresta tietojoukosta Käsitellään rakennetta, jossa tietojoukon yksittäisten alkioiden välillä voi olla yhteyksiä, jotka yksilöivät alkion suhteen muihin alkioihin (verkot) Käsitellään koordinaattiavaruudessa olevaa kokonaisuutta 15.9.2015 Tietorakenteet ja algoritmit Y 63
4.2 Algoritmien vertailu Jos sama asia voidaan toteuttaa eri tavoin, täytyy jotenkin pystyä arvioimaan, mikä toteutus on kulloinkin hyvä Vertailukriteereitä on monia: 1. Algoritmin askelmäärä suhteessa käsiteltävän tiedon määrään ü ü ü Pahin mahdollinen askelmäärä Keskimääräinen askelmäärä Tasattu askelmäärä => ALGORITMIANALYYSI 15.9.2015 Tietorakenteet ja algoritmit Y 64
Algoritmien vertailu / kriteereitä 2. Algoritmin kuluttama todellinen cpu-aika (usein ongelmallinen arvioitava) 3. Algoritmin/tietorakenteen vaatima muistitila suhteessa käsiteltävän tiedon määrään 4. Laskennalliseen ongelmaan liittyvät kriteerit (esim. vakaus (stabiilius) järjestämismenetelmissä) 15.9.2015 Tietorakenteet ja algoritmit Y 65
4.3 Algoritmien toteutus ja esittäminen Ohjelman ylläpidettävyyden kannalta on ehdottomasti järkevää toteuttaa tärkeä algoritmi siten, että sen mahdollinen vaihtaminen tehokkaampaan vaikuttaa mahdollisimman vähän muuhun ohjelmaan Käytetään abstrakteja tietotyyppejä Usein algoritmit esitetään pseudokielellä (á la Pascal) ja jätetään toteutuksen pienimmät yksityiskohdat avoimiksi Algoritmin perusajatusta on helpompi ymmärtää, kun ei tarvitse kiinnittää huomiota ohjelmointikielen syntaksiin Kuvaus on kieliriippumaton 15.9.2015 Tietorakenteet ja algoritmit Y 66
4.4 Iteratiiviset ohjelmat (vrt. algoritmin määritelmä) syöte peräkkäisyys Esim. print_list public void print_list(listnode head){ ListNode list; /* list: kulkija */ } list = head.next; if (list == z) System.out.print("List is empty"); else { while (list!= z) { System.out.print(list.data+" "); list = list.next; } } System.out.println(); haarau- tuminen toisto peräkkäisyys peräkkäisyys peräkkäisyys tulos(te) Luentotehtävä: Vastaako vuokaavion rakenne em. ohjelmaa? 15.9.2015 Tietorakenteet ja algoritmit Y 67
4.5 REKURSIO Rekursiivinen ohjelma Kutsuu itseään Rekursiivinen rakenne Rakenne sisältyy itseensä Rekursiivinen funktio On määritelty itsensä avulla Esim. Fibonacci-luvut: X(i) = X(i-1) + X(i-2), X(0) = X(1) = 1 15.9.2015 Tietorakenteet ja algoritmit Y 68
Rekursio ei voi jatkua loputtomiin Täytyy löytyä päätösehto jonka toteutuminen lopettaa rekursion Esim. Kertoma: Rekursio: N! = N(N-1)! Päätösehto: 0! = 1 15.9.2015 Tietorakenteet ja algoritmit Y 69
Rekursion neljä kultaista sääntöä: 1. Perustapaukset (ratkaistavissa ilman rekursiota) 2. Edistyminen (liikutaan perustapausta kohti) 3. Oletus (kaikki rekursiiviset kutsut toimivat) 4. Vältä turhaa työtä (jokainen tapaus ratkaistaan vain kerran) 15.9.2015 Tietorakenteet ja algoritmit Y 70
Esim. Kertoma rekursiivisena: int factorial(int n) /* n: askeltaja */ { if (n==0) return 1; else return factorial(n-1)*n; } Esim. Kertoma ei-rekursiivisena: int factorial(int n) /* n: kiintoarvo */ { int i,fact; fact = 1; /* fact: kokooja */ for (i=2; i<=n; i++) /* i: askeltaja */ fact = fact*i; return fact; } 15.9.2015 Tietorakenteet ja algoritmit Y 71
Esim. Fibonacci-luvut: int fibonacci(int n) { if (n<=1) return 1; else return fibonacci(n-1)+fibonacci(n-2); } F5 F6 F4 {Rikkoo neljättä sääntöä} F4 F3 F3 F2 Parempi toteuttaa eirekursiivisena F3 F2 F2 F1 F2 F1 F1 F0 F2 F1 F1 F0 F1 F0 F1 F0 F1 F0 15.9.2015 Tietorakenteet ja algoritmit Y 72
Rekursiohistoriapuu Puurakenne, jossa solmu jokaista rekursiokutsua kohti Solmut aktivoituvat ns. esijärjestyksessä (ks. puiden läpikäynti) Ensimmäistä kutsua vastaa puun juuri Pinokehys aktiivinen, kunnes kaikki alipuut on käyty läpi Pinokehys poistuu, kun rekursio palaa solmusta Esim. Fibonaccin luvut: int fibonacci(int n) { if (n<=1) return 1; else return fibonacci(n-1)+fibonacci(n-2); } 15.9.2015 Tietorakenteet ja algoritmit Y 73
Esim. Hanoin tornit (Edouard Lucas, 1883): Siirrä renkaat toiseen tappiin yksi kerrallaan niin, että isompi rengas ei koskaan ole pienemmän päällä: Mistä Minne Vi a N K2.17? 15.9.2015 Tietorakenteet ja algoritmit Y 74
Esim. Hanoin tornit (Edouard Lucas, 1883): Ratkaisu rekursion avulla: Mistä Minne Vi a N-1 N-1 1 K2.17 15.9.2015 Tietorakenteet ja algoritmit Y 75
void hanoi(int N, int mista, int minne, int via) { if (N==1) printf( Siirrä rengas tapista %d tappiin %d kiitos\n, mista, minne); else { hanoi(n-1, mista, via, minne); hanoi(1, mista, minne, via); // printf hanoi(n-1, via, minne, mista); } } Mistä Minne Vi a Kotitehtävä: Ohjelmoi hanoi haluamallasi ohjelmointikielellä ja testaa, että se toimii! K2.17 15.9.2015 Tietorakenteet ja algoritmit Y 76
Hanoin tornien rekursiohistoriapuu Esim. hanoin(3, 1, 2, 3) void hanoi(int N, int mista, int minne, int via) { if (N==1) printf( Siirrä rengas tapista %d tappiin %d kiitos\n, mista, minne); else { hanoi(n-1, mista, via, minne); hanoi(1, mista, minne, via); // printf hanoi(n-1, via, minne, mista); } } h(3,1,2,3) Mistä Minne Vi a K2.17 h(2,1,3,2) h(1,1,2,3) 15.9.2015 Tietorakenteet ja algoritmit Y 77
Rekursiohistoriapuu Esim. hanoi(3, 1, 2, 3) void hanoi(int N, int mista, int minne, int via) { if (N==1) printf( Siirrä rengas tapista %d tappiin %d kiitos\n, mista, minne); else { hanoi(n-1, mista, via, minne); hanoi(1, mista, minne, via); // printf hanoi(n-1, via, minne, mista); } } h(3,1,2,3) h(2,1,3,2) h(1,1,2,3) h(2,3,2,1) h(1,1,2,3) h(1,1,3,2) h(1,2,3,1) h(1,3,1,2) h(1,3,2,1) h(1,1,2,3) 15.9.2015 Tietorakenteet ja algoritmit Y 78