Tietorakenteet ja algoritmit Lineaariset perustietorakenteet Ari Korhonen 15.9.2015 Tietorakenteet ja algoritmit Y 1 2. TIETORAKENTEIDEN TOTEUTUSPERIAATTEITA • 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; double sum; Sortable table[1000]; § /* count: askeltaja */ /* sum: kokooja */ /* 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) § 1 2 3 4 5 15.9.2015 esim. integer Pythonissa struct _intblock { struct _intblock *next; PyIntObject objects[N_INTOBJECTS]; }; typedef struct _intblock PyIntBlock; 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; double *p; p = &table[0]; for (int i = 0; i < 1000; i++) { sum += *p; p=p+1; } § 15.9.2015 /* p: askeltaja */ /* table: järjestelijä */ /* i: askeltaja */ Sama kuin double sum = 0; for (int i = 0; i < 1000; i++) sum += table[i]; § /* sum: kokooja */ /* sum: kokooja */ /* i: askeltaja */ /* table: järjestelijä */ Tässä esimerkissä osoitinten käyttö tarpeetonta, mutta C-kielessä esim. merkkijonoja käsitellään usein osoittimien avulla. Tietorakenteet ja algoritmit Y 5 2.1 Peruskäsitteitä / Muuttujat § 15.9.2015 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. 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. § § § 15.9.2015 Niiden koko on sidottu määrittelyyn On olemassa myös dynaamisia taulukoita Dynaamiset tietorakenteet luodaan osoitinmuuttujien avulla (C) tai oliorakenteina (Java, Python). 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 § § § 15.9.2015 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. 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. § § 15.9.2015 taulukko, linkitetty lista, pino, jono Tällaista rakennetta voidaan käyttää esim. • yksinkertaisena hakurakenteena, • tilapäisenä tallennusrakenteena. 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 • Binäärinen hakupuu • Taulukko • Hajautustaulukko 1 D 3 2 A B G C Talletusrakenne vai semanttinen rakenne: § 15.9.2015 Rakenne voi olla puhdas talletusrakenne tai abstrakti tietotyyppi, jolla on jokin semantiikka 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 15.9.2015 q ja algoritmit Yr Tietorakenteet 17 § 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; p 20 10 13 K2.1 Esim. 15.9.2015 11 q r Tietorakenteet ja algoritmit Y 18 § Alkion lisääminen on helppoa, kun käsillä on osoitin siihen alkioon, jonka jälkeen uusi alkio sijoitetaan p 20 10 13 11 K2.3 (C) q 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; p 20 10 13 11 K2.3 q r 15.9.2015 99 r Tietorakenteet ja algoritmit Y 99 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 K2.5 Listan loppumisen tarkastaminen: 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: temp = get_node(); // malloc temp->data = key; temp->next = head->next; head->next = temp; tilapäissäilö */ /* temp->data: kiintoarvo */ /* temp->next: kiintoarvo */ /* 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; ListNode z = new ListNode(null); /* kiintoarvo */ /* 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] next[0..N] i 0 1 2 3 4 5 6 p 15.9.2015 arvot osoittimet data head z T I L S A h e a d L next 4 1 6 5 3 2 1 I S T A z K2.7 Tietorakenteet ja algoritmit Y 28 § 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 15.9.2015 def addLast(self, item): … 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: 15.9.2015 • TULOSTUS • HAKU • LISÄYS • POISTO • PÄIVITYS • TYHJÄN LISTAN LUOMINEN • N:NNEN ALKION PALAUTTAMINEN • ONKO LISTA TYHJÄ? … Tietorakenteet ja algoritmit Y 33 § Eri operaatioitten vaatima aika: • • • • § • 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 15.9.2015 N N/2 (epäonnistunut: N) 1 N/2 Lista voidaan pitää järjestyksessä, jolloin (epäonnistunut) haku on nopeampi • § TULOSTUS HAKU LISÄYS POISTO 17 20 10 13 Tietorakenteet ja algoritmit Y 99 K2.6 34 2.5 Tapausesimerkki POLYNOMI ∑ ai xi § 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; § 15.9.2015 Ei rajaa polynomin asteluvulle! 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 - Unioni - Komplementti - Koko (= alkioiden määrä) • ∈ - Kuuluu joukkoon? Set intersection(Set A, Set B) Set union(Set A, Set B) Set compl(Set A, Set superSet) int size(Set A) 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 • • • • • 15.9.2015 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ä 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 15.9.2015 • 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 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. § 15.9.2015 • yksinkertaisena hakurakenteena, • tilapäisenä tallennusrakenteena. • Taulukko, lista Seuraavaksi tarkastellaan eräitä tärkeitä lineaarisia abstrakteja tietotyyppejä. 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: 15.9.2015 • 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ä 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 § isEmpty() ⇔ (sp == -1) § Taulukkototeutuksessa pinolle varattu tila voi loppua 15.9.2015 sp Tietorakenteet ja algoritmit Y 7 6 5 4 3 2 1 0 K2.13 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ä 15.9.2015 § top == null tai § Header == Z (jos käytetään erillisiä head ja z--alkioita) Tietorakenteet ja algoritmit Y 46 Pinon sovelluksia § Ohjelmointikielessä lausesulkujen tarkastus: kullekin alkusululle löytyy oikeantyyppinen loppusulku • • Kielessä voi esiintyä useita eri sulkutyyppejä, esim. Ckielessä (,); [,]; {,} Sulkuvirheet (esim. ”{(})”) voivat usein sotkea kääntäjän toiminnan pahoin § Syötevirran kääntäminen päinvastaiseen järjestykseen § Ajonaikainen pino (aliohjelmakutsut): • • 15.9.2015 Kutsuvan ohjelman tila (=rekisterit) ja kutsun paikka (=program counter) pinoon Aliohjelmasta palattaessa voidaan palauttaa alkuperäinen tila 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 ü • 15.9.2015 Jos pino on tyhjä (isEmpty) tai sulku on väärän tyyppinen ⇒ virhe Algoritmin päättyessä pinon tulee olla tyhjä Tietorakenteet ja algoritmit Y 48 Lausekkeen arvon laskeminen • Miten evaluoida lausekkeen arvo? • Infix-notaatio: 5 * ( ( 9 + 8 ) * 4 * 6 + 7 ) 15.9.2015 § Miten tallentaa välitulokset? § Mikä on toimintajärjestys, kun lauseke luetaan ohjelmalle merkki merkiltä? 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 15.9.2015 5 * ( ( 9 + 8 ) * 4 * 6 + 7 ) tyhjä Pino Tuloste 5 * *( *(( 9 *((+ *( *(* *(* *(+ * Tietorakenteet ja algoritmit Y 8 + 4 * 6 * 7 + * 52 § POSTFIX-lausekkeen arvo voidaan laskea pinon avulla § Esim. lauseke 598+4*6*7+* 15.9.2015 Input Pino 5 9 8 + 4 * 6 * 7 + * empty 5 5 9 5 9 8 5 17 5 17 4 5 68 5 68 6 5 408 5 408 7 5 415 2075 Tietorakenteet ja algoritmit Y 53 3.2 § 15.9.2015 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). Tietorakenteet ja algoritmit Y 54 § Jonon toteutus sirkulaarisena taulukkona Jono[0 .. MAX-1] l ast fi r s t 0 1 2 3 4 5 6 7 MAX 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]; first = (first+1) % MAX; return tmp; § /* tmp: tilapäissäilö */ /* first:askeltaja */ First(): return Jono[first]; § 15.9.2015 IsEmpty(): (last == first); 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 s t l ast K2.16 15.9.2015 Tietorakenteet ja algoritmit Y 57 § struct node *first, *last; struct node *temp; § 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 /* first, last: kulkijat /* tmp: tilapäissäilö */ Tietorakenteet ja algoritmit Y */ 58 Jonon sovelluksia § Esim. Printterijono § Puskuri • • • • • § Diskreetti simulointi • § 15.9.2015 tiedon välivarasto tietoa tulee tietoa lähtee tiedon järjestys säilyy Esim. tulostettava tiedosto menee puskurin kautta Esim. liikenne, tietoliikenne, palvelut Verkkoalgoritmit (esim. leveyssuuntainen haku eli BFS) 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: § 15.9.2015 Määrittele abstrakti tietotyyppi pakka 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: • • • • 15.9.2015 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 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 syöte (vrt. algoritmin määritelmä) 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 peräkkäisyys toisto 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 • • Rekursiivinen rakenne • § Kutsuu itseään 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: Päätösehto: 15.9.2015 N! = N(N-1)! 0! = 1 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); } {Rikkoo neljättä sääntöä} § F4 Parempi toteuttaa eirekursiivisena F3 F2 F1 15.9.2015 F1 F5 F4 F3 F2 F1 F6 F2 F0 F1 F3 F1 F0 F2 F1 F2 F1 F1 F0 F0 F0 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ä: Mi s t ä Mi nne Vi a N K2.17 15.9.2015 ? Tietorakenteet ja algoritmit Y 74 § Esim. Hanoin tornit (Edouard Lucas, 1883): Ratkaisu rekursion avulla: Mi s t ä Mi nne 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); } } Mi s t ä Kotitehtävä: Ohjelmoi hanoi haluamallasi ohjelmointikielellä ja testaa, että se toimii! 15.9.2015 Tietorakenteet ja algoritmit Y Mi nne Vi a K2.17 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); } } Mi s t ä Mi nne Vi a K2.17 h(3,1,2,3) 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) 15.9.2015 h(1,1,3,2) h(2,3,2,1) h(1,1,2,3) h(1,2,3,1) Tietorakenteet ja algoritmit Y h(1,3,1,2) h(1,3,2,1) h(1,1,2,3) 78
© Copyright 2025