Algoritmien suunnittelumenetelmiä

Samankaltaiset tiedostot
Lineaariset perustietorakenteet

REKURSIO. Rekursiivinen ohjelma Kutsuu itseään. Rekursiivinen rakenne. Rakenne sisältyy itseensä. Rekursiivinen funktio. On määritelty itsensä avulla

Tietorakenteet ja algoritmit. Kertaus. Ari Korhonen

A TIETORAKENTEET JA ALGORITMIT

Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Tietorakenteet ja algoritmit - syksy

TIETORAKENTEET JA ALGORITMIT

Algoritmit 1. Luento 4 Ke Timo Männikkö

811312A Tietorakenteet ja algoritmit II Perustietorakenteet

Algoritmit 1. Luento 3 Ti Timo Männikkö

Sisällys. 18. Abstraktit tietotyypit. Johdanto. Johdanto

18. Abstraktit tietotyypit 18.1

Tieto- ja tallennusrakenteet

Pino S on abstrakti tietotyyppi, jolla on ainakin perusmetodit:

Algoritmit 2. Luento 2 To Timo Männikkö

9/18/02 1. Tietorakenteet ja algoritmit Y. Syksy Dipoli T

Algoritmit 2. Luento 2 Ke Timo Männikkö

1.1 Pino (stack) Koodiluonnos. Graafinen esitys ...

Tietorakenteet ja algoritmit

Algoritmit 2. Luento 7 Ti Timo Männikkö

Kaksiloppuinen jono D on abstrakti tietotyyppi, jolla on ainakin seuraavat 4 perusmetodia... PushFront(x): lisää tietoalkion x jonon eteen

T /253 Tietorakenteet ja algoritmit T/Y

Rakenteiset tietotyypit Moniulotteiset taulukot

useampi ns. avain (tai vertailuavain) esim. opiskelijaa kuvaavassa alkiossa vaikkapa opintopistemäärä tai opiskelijanumero

Tietorakenteet ja algoritmit

3. Binääripuu, Java-toteutus

A TIETORAKENTEET JA ALGORITMIT

Algoritmit 1. Demot Timo Männikkö

Imperatiivisen ohjelmoinnin peruskäsitteet. Meidän käyttämän pseudokielen lauseiden syntaksi

Algoritmit 1. Luento 6 Ke Timo Männikkö

Algoritmit 2. Luento 4 To Timo Männikkö

Muuttujien roolit Kiintoarvo cin >> r;

Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit

Sisältö. 2. Taulukot. Yleistä. Yleistä

Rajapinta (interface)

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Listarakenne (ArrayList-luokka)

Kääreluokat (oppikirjan luku 9.4) (Wrapper-classes)

2. Seuraavassa kuvassa on verkon solmujen topologinen järjestys: x t v q z u s y w r. Kuva 1: Tehtävän 2 solmut järjestettynä topologisesti.

Sisältö. 22. Taulukot. Yleistä. Yleistä

ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Tietorakenneluokkia 2: HashMap, TreeMap

Abstraktit tietotyypit. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Luento 4 Aliohjelmien toteutus

Jakso 4 Aliohjelmien toteutus

Algoritmit 1. Demot Timo Männikkö

Tietueet. Tietueiden määrittely

Tietorakenteet, laskuharjoitus 3, ratkaisuja

Algoritmit 1. Luento 12 Ti Timo Männikkö

Algoritmit 2. Luento 3 Ti Timo Männikkö

Algoritmit 2. Luento 8 To Timo Männikkö

lähtokohta: kahden O(h) korkuisen keon yhdistäminen uudella juurella vie O(h) operaatiota vrt. RemoveMinElem() keossa

Algoritmit ja tietorakenteet / HL Copyright Hannu Laine

Algoritmit 2. Luento 14 Ke Timo Männikkö

Algoritmit 1. Luento 1 Ti Timo Männikkö

Tehtävän V.1 ratkaisuehdotus Tietorakenteet, syksy 2003

Algoritmit 2. Luento 4 Ke Timo Männikkö

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Algoritmit 2. Luento 3 Ti Timo Männikkö

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Algoritmit 1. Luento 7 Ti Timo Männikkö

Algoritmit 1. Luento 8 Ke Timo Männikkö

Ohjelmoinnin perusteet Y Python

Java-kielen perusteet

Ohjelmoinnin peruskurssien laaja oppimäärä

Kysymyksiä koko kurssista?

Jakso 4 Aliohjelmien toteutus

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Pythonin Kertaus. Cse-a1130. Tietotekniikka Sovelluksissa. Versio 0.01b

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

Tietorakenteet ja algoritmit

2. Perustietorakenteet

Olio-ohjelmointi Syntaksikokoelma

TAMPEREEN TEKNILLINEN YLIOPISTO

811312A Tietorakenteet ja algoritmit, , Harjoitus 7, ratkaisu

Algoritmit 1. Luento 11 Ti Timo Männikkö

Algoritmianalyysin perusteet

Java-kielen perusteet

Tietorakenteet. JAVA-OHJELMOINTI Osa 5: Tietorakenteita. Sisällys. Merkkijonot (String) Luokka String. Metodeja (public)

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Ohjelmoinnin jatkokurssi, kurssikoe

Algoritmit 1. Luento 12 Ke Timo Männikkö

Lyhyt kertaus osoittimista

TIE Tietorakenteet ja algoritmit 25

Muita linkattuja rakenteita

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Tietorakenteet ja algoritmit

A TIETORAKENTEET JA ALGORITMIT

811312A Tietorakenteet ja algoritmit III Lajittelualgoritmeista

Ohjelmoinnin perusteet Y Python

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

Tieto ja sen osoite (3) Jakso 3 Konekielinen ohjelmointi (TTK-91, KOKSI) Osoitinmuuttujat. Tieto ja sen osoite (5)

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Java-kielen perusteita

Ohjelmoinnin peruskurssien laaja oppimäärä

Luento 4 Aliohjelmien toteutus

Tutoriaaliläsnäoloista

Transkriptio:

Tietorakenteet ja algoritmit Algoritmien suunnittelumenetelmiä Ari Korhonen 24.9.2015 Tietorakenteet ja algoritmit 1

Algoritmien suunnittelumenetelmiä Lineaariset talletusrakenteet: taulukko, linkitetty lista Esimerkki: Polynomin toteutus Abstraktit tietotyypit: Pino, jono Esimerkki: Pinon käyttö postfix-lausekkeen evaluointiin Palautus Esimerkki: infix-postfix-muunnos pinon avulla Rekursiivisten algoritmien suunnitteluperiaatteita 24.9.2015 Tietorakenteet ja algoritmit 2

Tietotyypit Tietotyypit 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 (Scala, Java, Python). 24.9.2015 Tietorakenteet ja algoritmit 3

Dynaamiset tietorakenteet 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ä. Scalassa, 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. 24.9.2015 Tietorakenteet ja algoritmit 4

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. 24.9.2015 Tietorakenteet ja algoritmit 5

Tietorakenteista Tietorakenne voidaan luokitella kahdella tasolla Talletusrakenne on rakenne, joka sisältää joukon dataalkioita jollain tavalla talletettuna (esim. peräkkäin) ottamatta mitään kantaa alkioiden sisältöön tai miten niitä käsitellään. Esim. taulukko, linkitetty lista, binääripuu Abstrakti tietotyyppi (ADT) sisältää joukon data-alkioita, joilla on jokin semanttinen merkitys (esim. hakuavain) Esim. hakemisto, prioriteettijono Abstraktit tietotyypit toteutetaan talletusrakenteiden avulla ja niihin liittyy joukko operaatioita, joiden avulla alkioita käsitellään. Esim. haetaan jokin alkio, jolla on tunniste (avain), lisätään tiettyä avainta vastaava alkio. 24.9.2015 Tietorakenteet ja algoritmit 6

Tietorakenteista 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 24.9.2015 Tietorakenteet ja algoritmit 7

Tietorakenteista 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, Scala: Array, Vector, List, HashMap, 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. 24.9.2015 Tietorakenteet ja algoritmit 8

2.2 Yleistä Alkion saavutettavuus talletusrakenteissa: Mitä eroa? Taulukko Tietue Linkitetty lista Binääripuu Verkko Alkion paikka voidaan laskea vakioajassa tai sitten ei. 24.9.2015 Tietorakenteet ja algoritmit 9

Tietorakenteista 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 24.9.2015 Tietorakenteet ja algoritmit 10

Tietorakenteista: Linkitetty lista (linked list) 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 24.9.2015 Tietorakenteet ja algoritmit 11 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 24.9.2015 Tietorakenteet ja algoritmit 12 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 24.9.2015 Tietorakenteet ja algoritmit 13

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? 24.9.2015 Tietorakenteet ja algoritmit 14

Suunnittelussa kannattaa huomioida myös ylläpidettävyys! Erillisen Header-alkion ansiosta 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)... 24.9.2015 Tietorakenteet ja algoritmit 15

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; 24.9.2015 Tietorakenteet ja algoritmit 16

Eri operaatioitten vaatima aika: TULOSTUS N HAKU N/2 (epäonnistunut: N) LISÄYS 1 POISTO N/2 Linkitetty lista (mutable) 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) 24.9.2015 Tietorakenteet ja algoritmit 17

24.9.2015 Tietorakenteet ja algoritmit 18

24.9.2015 Tietorakenteet ja algoritmit 19

24.9.2015 Tietorakenteet ja algoritmit 20

Tietorakenteista: 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, Scalan Vector)! 24.9.2015 Tietorakenteet ja algoritmit 21

Array (mutable) 24.9.2015 Tietorakenteet ja algoritmit 22

24.9.2015 Tietorakenteet ja algoritmit 23

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 24.9.2015 Tietorakenteet ja algoritmit 24

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"); 24.9.2015 Tietorakenteet ja algoritmit 25

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ä */ 24.9.2015 Tietorakenteet ja algoritmit 26

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(); 24.9.2015 Tietorakenteet ja algoritmit 27

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; 24.9.2015 Tietorakenteet ja algoritmit 28

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); 24.9.2015 Tietorakenteet ja algoritmit 29

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); 24.9.2015 Tietorakenteet ja algoritmit 30

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 24.9.2015 Tietorakenteet ja algoritmit 31 K2.7

24.9.2015 Tietorakenteet ja algoritmit 32

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 24.9.2015 Tietorakenteet ja algoritmit 33

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): 24.9.2015 Tietorakenteet ja algoritmit 34

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. 24.9.2015 Tietorakenteet ja algoritmit 35

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Ä? 24.9.2015 Tietorakenteet ja algoritmit 36

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; 24.9.2015 Tietorakenteet ja algoritmit 37

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! 24.9.2015 Tietorakenteet ja algoritmit 38

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!! 24.9.2015 Tietorakenteet ja algoritmit 39

Abstrakti tietotyyppi (abstract data type, ADT) Kun talletetulle tiedolle annetaan semanttinen merkitys (mitä tieto tarkoittaa) ja määritellään, mitä tiedolle saa tehdä, 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. 24.9.2015 Tietorakenteet ja algoritmit 40

Algoritmit suhteessa tietorakenteisiin Useimmat algoritmit käsittelevät jotain (abstraktia) 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 Pinon käyttö sen sijaan, että manipuloidaan linkitettyä listaa 24.9.2015 Tietorakenteet ja algoritmit 41

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,...) 24.9.2015 Tietorakenteet ja algoritmit 42

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ä 24.9.2015 Tietorakenteet ja algoritmit 43

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 24.9.2015 Tietorakenteet ja algoritmit 44

3. Lisää lineaarisista perustietorakenteista 3.1 Pino (stack) 3.2 Jono (queue) 3.3 Pakka (deque) 24.9.2015 Tietorakenteet ja algoritmit 45

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ä. 24.9.2015 Tietorakenteet ja algoritmit 46

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ä 24.9.2015 Tietorakenteet ja algoritmit 47

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 24.9.2015 Tietorakenteet ja algoritmit 48

Toteutus linkitettynä 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) 24.9.2015 Tietorakenteet ja algoritmit 49

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 Postfix-lausekkeen arvon laskeminen Infix-postfix-muunnos 24.9.2015 Tietorakenteet ja algoritmit 50

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 24.9.2015 Tietorakenteet ja algoritmit 51

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ä) 24.9.2015 Tietorakenteet ja algoritmit 52

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 24.9.2015 Tietorakenteet ja algoritmit 53

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? 24.9.2015 Tietorakenteet ja algoritmit 54

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ä 24.9.2015 Tietorakenteet ja algoritmit 55

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 24.9.2015 Tietorakenteet ja algoritmit 56

Lausekkeen arvon laskeminen Miten evaluoida lausekkeen arvo? Infix-notaatio: 5 * ( ( 9 + 8 ) * 4 * 6 + 7 ) (vrt. sama lauseke postfix-muodossa: 598+4*6*7+*) Mikä on toimintajärjestys, kun lauseke luetaan ohjelmalle merkki merkiltä? Miten toimitaan sulkujen kanssa? Miten tallentaa välitulokset? 24.9.2015 Tietorakenteet ja algoritmit 57

Palautus Periaate: palautetaan ongelma sellaiseksi ongelmaksi, joka osataan ratkaista! Oletus: osataan evaluoida lauseke postfix-muodossa 1) Muunnetaan lauseke pinon avulla postfix-muotoon: infix: 5 * ( ( 9 + 8 ) * 4 * 6 + 7 ) postfix: 5 9 8 + 4 * 6 * 7 + * 2) Evaluoidaan postfix-lauseke pinon avulla 24.9.2015 Tietorakenteet ja algoritmit 58

INFIX-POSTFIX-muunnos pinon avulla O(N) ajassa Luetaan Infix-lauseketta symboli (N kpl) 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 24.9.2015 Tietorakenteet ja algoritmit 59

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ä * 24.9.2015 Tietorakenteet ja algoritmit 60

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). 24.9.2015 Tietorakenteet ja algoritmit 61

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ä 24.9.2015 Tietorakenteet ja algoritmit 62

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); 24.9.2015 Tietorakenteet ja algoritmit 63

Jonon toteutus linkitettynä 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 24.9.2015 Tietorakenteet ja algoritmit 64

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); 24.9.2015 Tietorakenteet ja algoritmit 65

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) 24.9.2015 Tietorakenteet ja algoritmit 66

PAKKA (deque) Alkioita voidaan lisätä rakenteen molempiin päihin sekä poistaa molemmista päistä Vrt. korttipakka kädessä Määrittely jätetään kotitehtäväksi: Määrittele abstrakti tietotyyppi pakka 24.9.2015 Tietorakenteet ja algoritmit 67

Tietorakenteet ja algoritmit Algoritmit Ari Korhonen 24.9.2015 Tietorakenteet ja algoritmit 68

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 24.9.2015 Tietorakenteet ja algoritmit 69

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 24.9.2015 Tietorakenteet ja algoritmit 70

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) 24.9.2015 Tietorakenteet ja algoritmit 71

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; 24.9.2015 Tietorakenteet ja algoritmit 72

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 Mutta: voitaisiin muuntaa lineaarisessa ajassa toimivaksi taulukoinnilla! F2 F3 F2 F2 F1 F2 F1 F1 F0 F1 F0 F1 F1 F0 F1 F0 F1 F0 24.9.2015 Tietorakenteet ja algoritmit 73

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); 24.9.2015 Tietorakenteet ja algoritmit 74

Dynaaminen ohjelmointi Dynamic Programming Jaetaan ongelma (rekursiivisesti) osaongelmiin, joita yhdistelemällä alkuperäinen ongelma ratkeaa Mitä jos sama pienempi osaongelma joudutaan ratkaisemaan useaan kertaan? Tämä rikkoo rekursion 4. kultaista sääntöä! Vrt. Hajoita ja hallitse (esim. Quicksort), jossa sama aliongelma esiintyy vain kerran Ratkaisuja Top-down: memoization / taulukointi tai Bottom-up: koostaminen 24.9.2015 Tietorakenteet ja algoritmit 75

Taulukointi Vrt. Fibonaccin luvut: Taulukoimalla: var arr = new Array[Int](MAX_N); def fib_r(n: Int): Int = { if (n <= 1) 1 else { fib_r(n - 1) + fib_r(n - 2) def fib_m(n: Int): Int = { if (n <= 1) 1 else { if (arr(n) == 0) arr(n) = fib_m(n - 1) + fib_m(n - 2) arr(n) Esim. Fibonaccin luvut voidaan laskea pitämällä kirjaa jo lasketuista tapauksista Yleisesti pidetään kirjaa (top-down) jo laskettujen aliongelmien ratkaisuista ja tehdään laskentaa vain, jos ratkaisua ei vielä tunneta 24.9.2015 Tietorakenteet ja algoritmit 76

Koostaminen Esim. Fibonaccin luvut voidaan laskea myös lähtemällä liikkeelle tapauksista old = older = 1 ja laskemalla (bottom-up) silmukassa current = old + older ja päivittämällä old & older def fib_iter(n: Int) = { var old, older, current = 1 for (i <- 1 until n) { older = old old = current current = old + older current Yleisesti: koostetaan tunnetuista aliongelmien ratkaisuista monimutkaisempia ratkaisuja 24.9.2015 Tietorakenteet ja algoritmit 77

Luentotehtävä Analysoi seuraavien neljän algoritmin suoritusaika ja muistin tarve def fib_r(n: Int): Int = { if (n <= 1) 1 else { fib_r(n - 1) + fib_r(n - 2) var arr = new Array[Int](45+1); def fib_r_2(n: Int) = { @scala.annotation.tailrec def fib_inner(n: Int, current: Int, old: Int): Int = if (n > 1) fib_inner(n-1, current + old, current) else current fib_inner(n, 1, 1) def fib_m(n: Int): Int = { if (n <= 1) 1 else { if (arr(n) == 0) arr(n) = fib_m(n - 1) + fib_m(n - 2) arr(n) def fib_iter(n: Int) = { var old, older, current = 1 for (i <- 1 until n) { older = old old = current current = old + older current 24.9.2015 Tietorakenteet ja algoritmit 78

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? 24.9.2015 Tietorakenteet ja algoritmit 79

Esim. Hanoin tornit (Edouard Lucas, 1883): Ratkaisu rekursion avulla: Mistä Minne Vi a N-1 N-1 1 K2.17 24.9.2015 Tietorakenteet ja algoritmit 80

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 24.9.2015 Tietorakenteet ja algoritmit 81

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) 24.9.2015 Tietorakenteet ja algoritmit 82

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) 24.9.2015 Tietorakenteet ja algoritmit 83

Ensi kerraksi Tee viikkojen 38-39 viikkoharjoitukset (viikon 38 DL on jo maanantaina!) Tutustu rekursion käsitteeseen esim. kalvoista löytyvän Hanointornit esimerkin ja rekursiohistoriapuun avulla Mikä on Hanoin-tornit ongelman ratkaisevan algoritmin aikakompleksisuus? Muodosta rekursioyhtälö ja ratkaise se! Tee viikon 40 luentotehtävä Huom! kahden seuraavan luennon järjestys on vaihtunut: ensi viikolla on rinnakkaisalgoritmeja eikä järjestämismenetelmiä 24.9.2015 Tietorakenteet ja algoritmit 84