Luku 4. Tietorakenteet funktio-ohjelmoinnissa. 4.1 Äärelliset kuvaukset

Samankaltaiset tiedostot
Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Abstraktit tietotyypit. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Laajennetaan vielä Ydin-Haskellia ymmärtämään vakiomäärittelyt. Määrittely on muotoa

v 1 v 2 v 3 v 4 d lapsisolmua d 1 avainta lapsen v i alipuun avaimet k i 1 ja k i k 0 =, k d = Sisäsolmuissa vähint. yksi avain vähint.

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

A TIETORAKENTEET JA ALGORITMIT

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Algoritmit 2. Luento 2 To Timo Männikkö

Algoritmit 2. Luento 2 Ke Timo Männikkö

Tämän vuoksi kannattaa ottaa käytännöksi aina kirjoittaa uuden funktion tyyppi näkyviin, ennen kuin alkaa sen määritemää kirjoittamaan.

AVL-puut. eräs tapa tasapainottaa binäärihakupuu siten, että korkeus on O(log n) kun puussa on n avainta

Kierros 4: Binäärihakupuut

Hakupuut. tässä luvussa tarkastelemme puita tiedon tallennusrakenteina

Binäärihaun vertailujärjestys

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Miten käydä läpi puun alkiot (traversal)?

CS-A1140 Tietorakenteet ja algoritmit

Algoritmit 2. Luento 5 Ti Timo Männikkö

TIEA341 Funktio-ohjelmointi 1, kevät 2008

58131 Tietorakenteet ja algoritmit Uusinta- ja erilliskoe ratkaisuja (Jyrki Kivinen)

TKT20001 Tietorakenteet ja algoritmit Erilliskoe , malliratkaisut (Jyrki Kivinen)

14 Tasapainotetut puurakenteet

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Algoritmit 2. Luento 6 Ke Timo Männikkö

Tietorakenteet, laskuharjoitus 6,

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

Tyyppejä ja vähän muutakin. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Tietorakenteet ja algoritmit - syksy

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Algoritmit 1. Luento 8 Ke Timo Männikkö

811312A Tietorakenteet ja algoritmit, , Harjoitus 5, Ratkaisu

2.4 Normaalimuoto, pohja ja laskentajärjestys 2.4. NORMAALIMUOTO, POHJA JA LASKENTAJÄRJESTYS 13

Algoritmit 2. Luento 7 Ti Timo Männikkö

TIEA341 Funktio-ohjelmointi 1, kevät 2008

58131 Tietorakenteet ja algoritmit (kevät 2016) Ensimmäinen välikoe, malliratkaisut

Tietorakenteet, laskuharjoitus 7, ratkaisuja

Algoritmit 2. Luento 5 Ti Timo Männikkö

Algoritmit 1. Luento 7 Ti Timo Männikkö

private TreeMap<String, Opiskelija> nimella; private TreeMap<String, Opiskelija> numerolla;

Algoritmit 2. Luento 6 To Timo Männikkö

Luku 3. Listankäsittelyä. 3.1 Listat

58131 Tietorakenteet (kevät 2008) 1. kurssikoe, ratkaisuja

(a) L on listan tunnussolmu, joten se ei voi olla null. Algoritmi lisäämiselle loppuun:

Algoritmit 2. Luento 4 To Timo Männikkö

58131 Tietorakenteet ja algoritmit (kevät 2013) Kurssikoe 1, , vastauksia

Algoritmit 2. Luento 3 Ti Timo Männikkö

Algoritmit 2. Luento 3 Ti Timo Männikkö

58131 Tietorakenteet ja algoritmit (kevät 2014) Uusinta- ja erilliskoe, , vastauksia

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

Laiska laskenta, korekursio ja äärettömyys. TIEA341 Funktio ohjelmointi Syksy 2005

Pinot, jonot, yleisemmin sekvenssit: kokoelma peräkkäisiä alkioita (lineaarinen järjestys) Yleisempi tilanne: alkioiden hierarkia

T Syksy 2004 Logiikka tietotekniikassa: perusteet Laskuharjoitus 7 (opetusmoniste, kappaleet )

811312A Tietorakenteet ja algoritmit Kertausta jälkiosasta

7. Tasapainoitetut hakupuut

Koe ma 1.3 klo salissa A111, koeaika kuten tavallista 2h 30min

Algoritmi on periaatteellisella tasolla seuraava:

58131 Tietorakenteet ja algoritmit (syksy 2015) Toinen välikoe, malliratkaisut

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

Ohjelmoinnin perusteet Y Python

5.5 Jäsenninkombinaattoreista

Tietorakenteet ja algoritmit Hakurakenteet Ari Korhonen

Luku 8. Aluekyselyt. 8.1 Summataulukko

5.3 Laskimen muunnelmia 5.3. LASKIMEN MUUNNELMIA 57

Datatähti 2019 loppu

811312A Tietorakenteet ja algoritmit, , Harjoitus 5, Ratkaisu

Algoritmit 2. Luento 10 To Timo Männikkö

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 2. helmikuuta 2012

Ohjelmoinnin perusteet Y Python

Algoritmit 1. Luento 6 Ke Timo Männikkö

B + -puut. Kerttu Pollari-Malmi

1.1 Tavallinen binäärihakupuu

Algoritmit 2. Luento 4 Ke Timo Männikkö

58131 Tietorakenteet (kevät 2009) Harjoitus 6, ratkaisuja (Antti Laaksonen)

TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 9. marraskuuta 2009

3. Hakupuut. B-puu on hakupuun laji, joka sopii mm. tietokantasovelluksiin, joissa rakenne on talletettu kiintolevylle eikä keskusmuistiin.

A TIETORAKENTEET JA ALGORITMIT KORVAAVAT HARJOITUSTEHTÄVÄT 3, DEADLINE KLO 12:00

58131 Tietorakenteet Erilliskoe , ratkaisuja (Jyrki Kivinen)

Ohjelmoinnin perusteet Y Python

Demo 7 ( ) Antti-Juhani Kaijanaho. 9. joulukuuta 2005

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

1 Puu, Keko ja Prioriteettijono

4. Joukkojen käsittely

Anna Kuikka Pyöräkatu 9 B Kuopio GSM: Opiskelijanro: 60219K. Prioriteettijonot

18. Abstraktit tietotyypit 18.1

Ydin-Haskell Tiivismoniste

Algoritmit 1. Luento 3 Ti Timo Männikkö

811312A Tietorakenteet ja algoritmit V Hash-taulukot ja binääriset etsintäpuut

Algoritmit 1. Luento 5 Ti Timo Männikkö

Pikalajittelu: valitaan ns. pivot-alkio esim. pivot = oikeanpuoleisin

Tämä tarina on Fibonaccin lukujen ongelman alkuperäinen muotoilu.

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Algoritmit 2. Luento 11 Ti Timo Männikkö

3. Binääripuu, Java-toteutus

A TIETORAKENTEET JA ALGORITMIT

811312A Tietorakenteet ja algoritmit III Lajittelualgoritmeista

811312A Tietorakenteet ja algoritmit II Perustietorakenteet

Kysymyksiä koko kurssista?

8. Puna-mustat puut ja tietorakenteiden täydentäminen

Mukautuvat järjestämisalgoritmit

Transkriptio:

Luku 4 Tietorakenteet funktio-ohjelmoinnissa Koska funktio-ohjelmoinnissa ei käytetä tuhoavaa päivitystä (sijoituslausetta ja sen johdannaisia), eivät läheskään kaikki valtavirtaohjelmoinnista tutut tietorakenteet toimi kuten voisi kuvitella. Chris Okasaki on kirjassaan Purely Functional Data Structures (Cambridge University Press, 1998) käsitellyt tätä ongelmaa, esittänyt tutuille tietorakenteille funktio-ohjelmointiin sopivia määritelmiä sekä uusia rakenteita, jotka ovat mahdollisia vain funktio-ohjelmoinnissa. Tämän luvun tarkoituksena on esitellä joitakin Okasakin tuloksia. 4.1 Äärelliset kuvaukset Sitä, mitä valtavirtaohjelmoijat sanovat assosiaatiotauluksi, funktio-ohjelmoijat kutsuvat äärelliseksi kuvaukseksi (finite map). Kyse on siis tietorakenteesta, johon voidaan tallettaa tietoa niin, että se on avaimella löydettävissä suhteellisen nopeasti. Valtavirtaohjelmoijan suosimia hajautustauluja ei funktioohjelmoinnissa voi käyttää; sen sijasta suosittuja ovat erilaiset hakupuuratkaisut. Äärellisen kuvauksen rajapinta sisältää funktiot tyhjän kuvauksen luomiseen, alkion etsimiseen avaimella ja avain-alkioparin lisäämiseen. Tämän voi toteut- 45

46 LUKU 4. TIETORAKENTEET FUNKTIO-OHJELMOINNISSA taa esimerkiksi binäärisellä hakupuulla: data BinaryTree key elt = BTNode (BinaryTree key elt) key elt (BinaryTree key elt) BTEmpty emptytree :: Ord key BinaryTree key elt emptytree = BTEmpty lookupintree :: Ord key BinaryTree key elt key Maybe elt lookupintree BTEmpty _ = Nothing lookupintree (BTNode lst key elt rst) key key < key = lookupintree lst key key == key = Just elt key > key = lookupintree rst key (Lisäys jätetään harjoitustehtäväksi.) Jos aineisto lisätään puuhun satunnaisessa järjestyksessä, on keskimääräinen haku- ja lisäysaika logaritminen (Θ(log n)). Pahimmassa tapauksessa kuitenkin tällainen naiivi binääripuu surkastuu linkitetyksi listaksi, esimerkiksi jos aineisto lisätään avaimen (<)-järjestyksessä. Parempi puurakenne saadaan, jos tietorakenteen operaatiot pitävät puun tasapainossa. Yksi tällainen tietorakenne on punamustat puut, joissa joka epätyhjällä solmulla on avain alkio-parin lisäksi väri, punainen tai musta. data Color = R B deriving Show data RBTree key elt = E N Color (RBTree key elt) (key, elt) (RBTree key elt) deriving Show Tässä määrittelyssä käytetään lyhyitä koostimien nimiä, koska se helpottaa operaatioiden määritelmien luettavuutta. Punamustalta puulta vaaditaan kaksi invarianttia (ominaisuutta, jotka pätevät rakenteen kaikilta ilmentymiltä): 1. Punaisella solmulla ei ole punaista lapsisolmua. 2. Jokainen polku juuresta tyhjään solmuun sisältää saman määrän mustia solmuja.

4.1. ÄÄRELLISET KUVAUKSET 47 Näiden invarianttien seurauksena puun syvin lehtisolmu on enintään kaksi kertaa niin syvällä kuin puun matalin lehtisolmu. Näin ollen n-solmuisen punamustan puun maksimisyvyys on 2 log(n + 1) eli Θ(log n). Tyhjän puun luontioperaatio emptyrbtree :: Ord key RBTree key elt ja puusta haku lookupinrbtree :: Ord key RBTree key elt key Maybe elt ovat samanlaisia kuin naiivissa binäärihakupuussa; hakuoperaatio jättää värin huomiotta. Koska puun maksimisyvyys on Θ(log n), on puusta haun asymptoottinen aikavaativuus logaritminen. Puuhun lisääminen on hieman mielenkiintoisempi tapaus: addtorbtree :: Ord key key elt RBTree key elt RBTree key elt addtorbtree key elt tree = N B left payload right where N _ left payload right = ins tree ins E = N R E (key, elt) E ins (N color l pl@(k, e) r) key < k = balance color (ins l)plr key > k = balance color rpl (ins r) otherwise = N color l (key, elt) r Lisäyksen tehtävänä on huolehtia siitä, että invariantit säilyvät. Uusi lehtisolmu väritetään punaiseksi, joten toinen invariantti (mustien määrä poluilla) pätee. Koska tämä saattaisi rikkoa ensimmäisen invariantin, täytyy sen ylisolmuja muokata niin, että ykkösinvariantti säilyy. Tämä tapahtuu siten, että tapauksissa key < k ja key > k koostin N korvataan funktiolla balance, jonka tehtävänä on korjata puu sellaiseksi, että ensimmäinenkin invariantti pätee. Huomautus 10 Hahmo x@p, missä x on muuttuja ja P on hahmo, tarkoittaa seuraavaa: Sovita P aivan kuin x@:ää ei olisikaan. Jos se epäonnistuu, x@p:n sovitus epäonnistuu yhtä lailla. Jos se onnistuu, sido P:n muuttujat tavalliseen tapaan ja lisäksi sido x siihen koko arvoon, johon P sopi. Esimerkiksi edellisen määrittelyn hahmo pl@(k, e) sopii mihin tahansa pariin; k tulee sidotuksi parin ensimmäiseen alkioon, e tulee sidotuksi parin jälkimmäiseen alkioon ja pl tulee sidotuksi koko pariin, joten pätee yhtälö pl = (k, e). Funktio balance tutkii puita, joiden juuri on musta ja joilla on kaksi (syvyyssuunnassa) perättäistä punaista alisolmua. Tällaisia epänormaaleita tilanteita on aina vain yhdellä polulla, koska tämä operaatio tehdään joka lisäyksen

48 LUKU 4. TIETORAKENTEET FUNKTIO-OHJELMOINNISSA jälkeen, joten vain viimeisin lisäys voi jättää puun tällä tavalla rikkinäiseen tilaan. Näissä tapauksessa se pyöräyttää puun sellaiseen muotoon, jossa syvyyssuunnassa keskellä ollut punainen solmu nostetaan juureksi ja sen ylä- ja alasolmu väritetään mustiksi ja sen kummankin alipuun juureksi. Muunlaiset puut se jättää rauhaan. balance :: Color RBTree key elt (key, elt) RBTree key elt RBTree key elt balance B (N R (N R a x b) y c) z d = N R (N B a x b) y (N B c z d) balance B (N R a x (N R b y c)) z d = N R (N B a x b) y (N B c z d) balance B a x (N R (N R b y c) z d) = N R (N B a x b) y (N B c z d) balance B a x (N R b y (N R c z d)) = N R (N B a x b) y (N B c z d) balance c a x b = N c a x b Huomaa, kuinka viimeistä tapausta lukuunottamatta tapaukset eroavat toisistaan vain parametriensa hahmoilla: =-merkin jäljessä tuleva määritelmä on kaikissa neljässä muussa tapauksessa sama! Kukin tapaus kannattaa piirtää kuvaksi, jotta balancen ymmärtäisi. Myös puille on mahdollista kehittää fold. Seuraava määritelmä käy listan läpi jälkijärjestyksessä: foldrbtree :: Ord key ((key, elt) β β) β RBTree key elt β foldrbtree _ e E = e foldrbtree f e (N _ lst pl rst) = foldrbtree f (f pl (foldrbtree f e rst)) lst Tämän avulla voidaan määritellä esimerkiksi funktio, joka muuttaa puun listaksi: convertrbtreetolist :: Ord key RBTree key elt [(key, elt)] convertrbtreetolist = foldrbtree (:) [] Myös map on mahdollinen: maprbtree :: Ord key (elt elt) RBTree key elt RBTree key elt maprbtree _ E = E maprbtree f (N c l (k, e) r) = N c (maprbtree f l)(k, f e) (maprbtree f r) 4.2 Abstraktit tietotyypit ja modulit Käytännön ohjelmoijaa harvemmin kiinnostaa se, miten jokin tietorakenne toimii pellin alla. Enemmän häntä kiinnostaa, mitä kaikkea sillä voi tehdä ja kuinka tehokkaasti. Abstrakti tietotyyppi (abstract datatype, ADT) on yleisnimitys tälle käytännön ohjelmoijan näkemykselle tietorakenteista.

4.2. ABSTRAKTIT TIETOTYYPIT JA MODULIT 49 Abstraktin tietotyypin arvot ovat mustia laatikoita. Tyypin yhteydessä määritellään joukko operaatioita, joiden välisestä yhteydestä voidaan sanoa jotain, sekä siitä, kuinka tehokas kukin operaatio on. Abstrakti tietotyyppi piilottaa tietotyypin rakenteen sekä operaatioiden toteutuksen sen käyttäjältä. Haskellissa abstrakti tietotyyppi saadaan aikaiseksi kirjoittamalla siitä moduli, joka julkistaa vain tyyppikoostimen ja joukon funktioita, mutta jättää piiloon tyypin (tieto)koostimet. Tämä tapahtuu kirjoittamalla moduli tiedostoon, jonka nimi alkaa isolla kirjaimella ja päättyy päätteeseen.hs. Tiedoston alkuun kirjoitetaan module Nimi (julkistuslista) where. Nimi on, kuten ennenkin on tullut mainittua, tiedoston nimi ilman.hs-päätettä. Suluissa oleva julkistuslista on luettelo pilkuilla toisistaan erotetuista koostin- ja vakionnimistä, jotka ko. moduli julkistaa. Kaikki muut nimet ovat modulin sisäisiä. Esimerkki 25 Edellä esitetty punamusta puu voidaan kirjoittaa seuraavaksi moduliksi: module RedBlackTree (RBTree, emptyrbtree, lookupinrbtree, addtorbtree, maprbtree, foldrbtree, convertrbtreetolist) where data Color = R B deriving (Show) data RBTree key elt = E N Color (RBTree key elt) (key, elt) (RBTree key elt) deriving (Show) emptyrbtree :: Ord key => RBTree key elt emptyrbtree = E lookupinrbtree :: Ord key => RBTree key elt -> key -> Maybe elt lookupinrbtree E _ = Nothing lookupinrbtree (N _ lst (key, elt) rst) key key < key = lookupinrbtree lst key key == key = Just elt key > key = lookupinrbtree rst key addtorbtree :: Ord key => key -> elt -> RBTree key elt -> RBTree key elt addtorbtree key elt tree = N B left payload right where N _ left payload right = ins tree ins E = N R E (key, elt) E ins (N color l pl@(k, e) r) key < k = balance color (ins l) pl r

50 LUKU 4. TIETORAKENTEET FUNKTIO-OHJELMOINNISSA key > k = balance color r pl (ins r) otherwise = N color l (key, elt) r balance :: Color -> RBTree key elt -> (key, elt) -> RBTree key elt -> RBTree key elt balance B (N R (N R a x b) y c) z d = N R (N B a x b) y (N B c z d) balance B (N R a x (N R b y c)) z d = N R (N B a x b) y (N B c z d) balance B a x (N R (N R b y c) z d) = N R (N B a x b) y (N B c z d) balance B a x (N R b y (N R c z d)) = N R (N B a x b) y (N B c z d) balance c a x b = N c a x b maprbtree :: Ord key => (elt -> elt) -> RBTree key elt -> RBTree key elt maprbtree _ E = E maprbtree f (N c l (k, e) r) = N c (maprbtree f l) (k, f e) (maprbtree f r) foldrbtree :: Ord key => ((key, elt) -> b -> b) -> b -> RBTree key elt -> b foldrbtree _ e E = e foldrbtree f e (N _ lst pl rst) = foldrbtree f (f pl (foldrbtree f e rst)) lst convertrbtreetolist :: Ord key => RBTree key elt -> [(key, elt)] convertrbtreetolist = foldrbtree (:) [] testtree = addtorbtree "auto" 4 $ addtorbtree "liikennemerkki" 14 $ addtorbtree "televisio" 9 $ addtorbtree "yö" 2 $ addtorbtree "ääliö" 5 $ addtorbtree "öljy" 4 $ emptyrbtree Huomautus 11 Operaattori ($) kuuluu varuskirjastoon ja määritellään näin: ($) :: (α β) α β f $ x = f x Sen hyödyllisyys piilee siinä, että sillä on kaikista operaattoreista alhaisin predesenssi ja se assosioi oikealle: näin f $ g $ h x on sama kuin f (g (h x)). Sillä voi siten vähentää sulkeiden määrää lausekkeissa. Modulia päästään käyttämään toisessa modulissa kirjoittamalla tiedoston alkuun module where -rivin jälkeen yksi tai useampi import-rivi, joka on jo-

4.2. ABSTRAKTIT TIETOTYYPIT JA MODULIT 51 ko muotoa import ToinenModuli jolloin tämän modulin nimiavaruuteen lisätään kaikki ToinenModuli-modulin julkistamat nimet, tai muotoa import ToinenModuli (nimi, nomen) jolloin tämän modulin nimiavaruuteen lisätään ToinenModuli-modulin julkistamista nimistä nimet nimi ja nomen, tai muotoa import ToinenModuli hiding (nimi, nomen) jolloin tämän modulin nimiavaruuteen lisätään ToinenModuli-modulin julkistamista nimistä kaikki muut paitsi nimet nimi ja nomen. Jokaisessa näistä muodoista voidaan lisäksi kirjoittaa import-avainsanan jälkeen avainsana qualified, jolloin ne ToinenModuli-modulin nimet, jotka ylipäätään lisätään tämän modulin nimiavaruuteen, lisätään muodossa ToinenModuli.nimi. Huomautus 12 Jos modulissa ei ole eksplisiittistä import-riviä varuskirjastolle Prelude, käsitellään tämä kuin siinä olisi implisiittinen import Prelude. Esimerkki 26 Tyypillinen abstrakti tietotyyppi on esimerkiksi Set. Se voidaan toteuttaa punamustilla puilla seuraavasti: module Set (emptyset, inset, listtoset, settolist, setunion, setcomprehension, setintersection, subset) where import RedBlackTree newtype Set a = MkSet (RBTree a ()) deriving Show emptyset :: Ord a => Set a emptyset = MkSet $ emptyrbtree unitset :: Ord a => a -> Set a

52 LUKU 4. TIETORAKENTEET FUNKTIO-OHJELMOINNISSA unitset a = MkSet $ addtorbtree a () emptyrbtree inset :: Ord a => a -> Set a -> Bool x inset (MkSet s) = case lookupinrbtree s x of Just () -> True Nothing -> False listtoset :: Ord a => [a] -> Set a listtoset l = MkSet $ foldr (uncurry addtorbtree) emptyrbtree $ zip l $ repeat () settolist :: Ord a => Set a -> [a] settolist (MkSet s) = map fst $ convertrbtreetolist s setunion :: Ord a => Set a -> Set a -> Set a (MkSet s) setunion (MkSet t) = MkSet $ foldrbtree (uncurry addtorbtree) s t setcomprehension :: Ord a => (a -> Bool) -> Set a -> Set a setcomprehension f = listtoset. filter f. settolist setintersection :: Ord a => Set a -> Set a -> Set a setintersection s t = setcomprehension ( inset s) t subset :: Ord a => Set a -> Set a -> Bool s subset t = and $ map ( inset t) $ settolist s Tehtävä 1 Määrittele FiniteMap.hs-moduli RedBlackTree.hs-modulin pohjalta. Määrittele sitten Set2.hs-moduli FiniteMap.hs-modulin pohjalta.