puuta tree hierarkkinen hierarchical



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

4. Puut. Kuva 4.1. Sukupuu Puun abstrakti tietotyyppi

5. Puut. Kuva 5.1. Sukupuu Puun abstrakti tietotyyppi

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

A TIETORAKENTEET JA ALGORITMIT

Hakupuut. tässä luvussa tarkastelemme puita tiedon tallennusrakenteina

Algoritmit 2. Luento 2 Ke Timo Männikkö

Algoritmit 2. Luento 2 To Timo Männikkö

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

Algoritmit 1. Luento 7 Ti Timo Männikkö

1.1 Tavallinen binäärihakupuu

Algoritmit 2. Luento 4 To Timo Männikkö

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

Algoritmit 2. Luento 4 Ke Timo Männikkö

Algoritmit 1. Luento 8 Ke Timo Männikkö

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.

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

Tietorakenteet ja algoritmit - syksy

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

7. Tasapainoitetut hakupuut

Kysymyksiä koko kurssista?

Algoritmit 2. Luento 7 Ti Timo Männikkö

Binäärihaun vertailujärjestys

811312A Tietorakenteet ja algoritmit, , Harjoitus 7, ratkaisu

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

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

1 Puu, Keko ja Prioriteettijono

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

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.

Algoritmit 2. Luento 6 To Timo Männikkö

Tietorakenteet, laskuharjoitus 3, ratkaisuja

Luku 8. Aluekyselyt. 8.1 Summataulukko

Algoritmit 1. Luento 12 Ti Timo Männikkö

Tietorakenteet, laskuharjoitus 7, ratkaisuja

10. Painotetut graafit

Algoritmit 1. Luento 12 Ke Timo Männikkö

Tietorakenteet, laskuharjoitus 6,

Algoritmit 2. Luento 5 Ti Timo Männikkö

Algoritmit 1. Luento 1 Ti Timo Männikkö

Algoritmit 1. Luento 3 Ti Timo Männikkö

Muita linkattuja rakenteita

Tietorakenteet ja algoritmit

8. Lajittelu, joukot ja valinta

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

A TIETORAKENTEET JA ALGORITMIT

Kierros 4: Binäärihakupuut

Algoritmit 2. Luento 6 Ke Timo Männikkö

Algoritmit 1. Luento 6 Ke Timo Männikkö

CS-A1140 Tietorakenteet ja algoritmit

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

811312A Tietorakenteet ja algoritmit, , Harjoitus 5, Ratkaisu

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

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

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

3. Binääripuu, Java-toteutus

6. Sanakirjat. 6. luku 298

TKT20001 Tietorakenteet ja algoritmit Erilliskoe , malliratkaisut (Jyrki Kivinen)

811312A Tietorakenteet ja algoritmit III Lajittelualgoritmeista

Algoritmit 2. Luento 5 Ti Timo Männikkö

Algoritmit 1. Luento 10 Ke Timo Männikkö

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

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

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

ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Algoritmit 1. Luento 4 Ke Timo Männikkö

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Datatähti 2019 loppu

Stabiloivat synkronoijat ja nimeäminen

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

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

Algoritmi on periaatteellisella tasolla seuraava:

18. Abstraktit tietotyypit 18.1

14 Tasapainotetut puurakenteet

Rajapinta (interface)

ITKP102 Ohjelmointi 1 (6 op)

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

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

Algoritmit 2. Luento 9 Ti Timo Männikkö

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

Luku 7. Verkkoalgoritmit. 7.1 Määritelmiä

B + -puut. Kerttu Pollari-Malmi

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

58131 Tietorakenteet ja algoritmit Uusinta- ja erilliskoe malliratkaisut ja arvosteluperusteet

Algoritmit 2. Luento 14 Ke Timo Männikkö

13. Loogiset operaatiot 13.1

4. Sekvenssit Astetta soveltavat sekvenssit

811312A Tietorakenteet ja algoritmit, , Harjoitus 5, Ratkaisu

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

Datatähti 2000: alkukilpailun ohjelmointitehtävä

Pino S on abstrakti tietotyyppi, jolla on ainakin perusmetodit:

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

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

3.3 Paraabeli toisen asteen polynomifunktion kuvaajana. Toisen asteen epäyhtälö

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

4. Joukkojen käsittely

1. (a) Seuraava algoritmi tutkii, onko jokin luku taulukossa monta kertaa:

58131 Tietorakenteet Erilliskoe , ratkaisuja (Jyrki Kivinen)

TIE Tietorakenteet ja algoritmit 261

Algoritmit 1. Luento 10 Ke Timo Männikkö

Transkriptio:

4. Puut Seuraavaksi käsitellään yhtä tärkeimmistä tietojenkäsittelytieteen ei-lineaarisista käsitteistä, puuta (tree). Puut ovat olleet keksintönä todellinen läpimurto, koska niissä luotiin tehokas eilineaari tapa järjestää nopeasti tietoa lineaarisiin tietorakenteisiin verrattuna. Järjestyssuhteet ovat puissa monipuolisemmat kuin pelkät edeltäjä ja seuraaja -relaatiot lineaaristen tietorakenteiden yhteydessä. Puussa suhde on hierarkkinen (hierarchical), jolloin jotkut oliot ovat toisten yläpuolella ja toiset alapuolellla. Tällöin käytetään yleensä nimikkeitä vanhempi, lapsi, esi-isä ja jälkeläinen. Nimikkeiden metafora voisi tulla kenties sukupuista, kuten kuvassa 4.1. 4. luku 151

Aabraham Iisak Ismael Jaakob Eesau Ruuben Simeon Leevi Kuva 4.1. Sukupuu. 4. luku 152

4.1. Puun abstrakti tietotyyppi Puu on abstrakti tietotyyppi, joka tallettaa alkiot hierarkkisesti. Päällimmäistä alkiota lukuunottamatta jokaisella alkiolla, solmulla (node), on vanhempi tai isä (parent, father) ja mahdollisesti lapsia (children). Toisinaan käytetään myös termejä edeltäjä ja seuraaja. Päällimmäistä solmua sanotaan juureksi (root), ja puu esitetään ylösalaisin (helpompi piirtää kasvusuunta alaspäin) kuvan 4.2. tavoin. 4. luku 153

Kännykkä Oyj T & K myynti osto tuotanto kotimaa ulkomaat laitteisto ohjelmisto pohjoismaat muu Eurooppa muut maanosat Afrikka Amerikat Aasia Australia Kuva 4.2. Kuvitteellisen yrityksen organisaatiokaavio puuna. Juurena on itse yritys. Sen lisäksi sisäsolmuina ovat myynti, tuotanto, ulkomaat ja muut maanosat. Ulkosolmuina eli lehtinä ovat muut solmut. 4. luku 154

Nimikkeitä ja perusominaisuuksia Puu T on solmujen joukko, joka tallettaa alkiot vanhempi-lapsisuhteessa: Puulla T on juurisolmu r, jolla ei ole vanhempaa. Jokaisella puun T muulla solmulla v on vanhempisolmu u. Juuri r on puun T jokaisen solmun v esivanhempi tai -isä (ancestor). Esivanhemman täsmällinen määritelmä on esitettävissä rekursion avulla. Solmun esivanhempi on nimittäin joko solmu itse tai solmun vanhemman esivanhempi. Voidaan ilmaista kääntäen, että solmu v on solmun u jälkeläinen (descendant), jos u on solmun v esivanhempi. 4. luku 155

Esim. 4.1. Java-ohjelman luokkienvälinen periytyminen muodostaa puun. Luokka java.lang on kaikkien muiden esivanhempi. Jos solmu u on solmun v vanhempi, niin v on solmun u lapsi (child). Vanhemman lapset ovat sisaruksia (siblings). Solmu on ulkosolmu (external node) eli lehti (leaf), jos sillä ei ole lapsia, muuten se on sisäsolmu (internal node). Puun alipuu (subtree) solmussa v käsittää v:n lisäksi kaikki tämän jälkeläiset puussa. Esim. 4.2. Tiedostot järjestetään useimmissa käyttöjärjestelmissä hierarkkisesti sisäkkäisiksi hakemistoiksi, jotka esitetään puuna (kuva 4.3.). Hakemistot muodostavat puun sisäsolmut ja tiedostot lehdet. Unix-käyttöjärjestelmässä puun juurta kutsutaan juurihakemistoksi (merk. symbolilla /). Se on tiedostojärjestelmän kaikkien hakemistojen esivanhempi. 4. luku 156

/user/rt/kurssit tietorakenteet neurolaskenta luennot viikkoharjoitukset harjoitustyö l1... l25 vh1... vh13 Kuva 4.3. Tämä on tiedostojärjestelmän osa, jossa tietorakenteet-kurssin alipuu sisältää 42 solmua. 4. luku 157

Puu on järjestetty (ordered), jos lasten välillä on määritelty lineaarinen järjestys, jolloin solmun lapset voidaan tunnistaa ensimmäisenä, toisena jne. Järjestystapa riippuu käyttötarkoituksesta. Tavallisesti se esitetään piirtämällä sisarussolmut vasemmalta oikealle. Esim. 4.3. Rakenteinen dokumentti, kuten kirja, voidaan järjestää hierarkkisesti puuna, jonka sisäsolmut ovat lukuja ja alilukuja ja jonka ulkosolmut eli lehdet ovat tekstikappaleita, taulukoita, kuvia, bibliografia jne. Juuri vastaa itse kirjaa. Tekstikappaleet voitaisiin vielä jakaa virkkeisiin, lauseisiin ja sanoihin, jotka sisältävät merkkejä. Puu on tässä esimerkki järjestetystä, sillä solmujen lapsien välillä on hyvin määritelty järjestys (kuva 4.4.). 4. luku 158

kirja esipuhe osa A osa B viitteet kpl kpl 1. luku 5. luku 6. luku 9. luku kpl kpl 1.1 luku 1.4 luku 5.1 luku 5.7 luku 6.1 luku 6.5 luku 9.1 luku 9.6 luku kpl kpl kpl kpl Kuva 4.4. Kirjan rakenne esitetty puuna. 4. luku 159

Binääripuu (binary tree) on järjestetty puu, jossa solmuilla on joko ei yhtään tai kaksi lasta. Tämä määritellään toisinaan aidoksi (strict) binääripuuksi, jolloin voidaan sanoa binääripuun solmun käsittävän ei yhtään, yhden tai kaksi lasta. Tässä esityksessä pitäydytään ensimmäiseen määritelmään ja jälkimmäinen, ei-aito tapaus, mielletään yleisen puun erääksi tapaukseksi. Tällöin binääripuun solmun ensimmäinen lapsi on vasen (left) ja toinen oikea (right). Solmun vasemman ja oikean lapsen mukaan nimetään ne juurinaan vasen ja oikea alipuu (subtree). Binääripuilla on lukuisia sovelluksia. Kaksi kuvataan suppeasti seuraavissa esimerkeissä. 4. luku 160

Esim. 4.4. Binääripuut ovat tärkeitä yhteyksissä, joissa halutaan esittää erilaisia tuloksia riippuen joidenkin testien tuloksista, joihin vastataan kyllä tai ei tai ylipäänsä jollakin binäärivastauksella (kaksiarvoisella muuttujalla). Kysymys on päätöspuista (decision trees). Näissä lehtisolmu v edustaa päätöstä, johon päädytään tilanteessa, että vastaukset esitettyihin kysymyksiin ovat puun kyseisen haaran mukaiset, ts. johtavat solmuun v. Kuvassa 4.5. on eräs esimerkki yksinkertaisesta päätöspuusta huimauspotilaiden korvalääketieteellisessä tasapainotutkimuksessa. 4. luku 161

kuulovaurio? kyllä ei hyvänlaatuista asentohuimausta ei huimauskohtausten esiintymismäärä? 1 > 1 ei hyvänlaatuista asentohuimausta päävamma? ei hyvänlaatuinen asentohuimaus kyllä ei hyvänlaatuista asentohuimausta Kuva 4.5. Binääri päätöspuu tutkittaessa huimauspotilaalta hyvänlaatuisen asentohuimauksen mahdollisuutta diagnoosina. 4. luku 162

Esim. 4.5. Aritmeettinen lauseke on esitettävissä puuna, jonka lehdet sisältävät muuttujat ja vakiot ja sisäsolmut sisältävät operaattoreita +, -, ja / (kuva 4.6.). Puun jokaisella solmulla on arvonaan jokin lausekkeen symboli. Jos solmu on lehti, sen arvo on muuttuja tai vakio. Jos se on sisäsolmu, sen arvo on lapsiin liittyvä operaatio. Tällainen aritmeettinen lauseke kuvataan binääripuuna, koska kullakin operaattorilla on täsmälleen kaksi operandia. Lisäksi pitää huomata operandeilla olevan määrätty järjestys, joka vaikuttaa tulokseen (paitsi operaattoreilla + ja ). Kääntäjän kääntäessä korkeantason kieltä väli- tai konekieleksi prosessin aikana aritmeettiset lausekkeet kuvataan abstraktilla tasolla puina, joista kuvan 4.6. tapaus voisi olla rajoitettu tapaus. 4. luku 163

/ + + 6 + 3 2 3 3 1 9 5 7 4 Kuva 4.6. Tämä on aritmeettista lauseketta esittävä binääripuu. Lauseke on (((3 + 1) 3) / ((9 5) + 2)) ((3 (7 4)) + 6)). 4. luku 164

Puun metodit Puun abstrakti tietotyyppi tallettaa alkiot paikkoihin, jotka sekvenssin tapaan määritellään suhteessa naapuripaikkoihin. Puun paikat (position) ovat solmuja. Naapuripaikat toteuttavat vanhempi-lapsi-suhteen, joka määrittelee kelvollisen puun. Näin ollen paikka puussa tarkoittaa solmua siinä. Puussa ovat seuraavat metodit merkittäviä: element(): Palauttaa alkion kyseisestä solmusta. Tulos: alkio container(): Palauttaa viittauksen puuhun, joka sisältää kyseisen solmun. Tulos: puu 4. luku 165

Puun todellinen voima syntyy metodeista, jotka käyttävät solmuja: root(): Palauttaa puun T juurisolmun. Puun ollessa tyhjä esiintyy virhe. Tulos: solmu parent(v): Palauttaa solmun v vanhemman. Solmun v ollessa juuri esiintyy virhe. Syöte: solmu Tulos: solmu children(v): Palauttaa luettelon solmun v lapsista. Syöte: solmu Tulos: luettelo solmuista Jos puu T on järjestetty, lapsien luettelo antaa ne järjestyksessä. Jos solmu v on lehti, luettelo on tyhjä. 4. luku 166

Edellisten lisäksi myös seuraavat ovat monesti tarpeen: isinternal(v): Testaa, onko solmu v sisäsolmu. Syöte: solmu Tulos: totuusarvo isexternal(v): Testaa, onko solmu v ulkosolmu eli lehti. Syöte: solmu Tulos: totuusarvo isroot(v): Testaa, onko solmu v juuri. Syöte: solmu Tulos: totuusarvo Nämä metodit ovat käteviä erilaisissa testeissä, jotka toteutetaan if-lauseissa ja while-silmukoissa. 4. luku 167

Oheiset yleisluontoiset metodit, jotka eivät sinänsä riipu puusta tietorakenteena, ovat hyödyllisiä puiden yhteydessä: size(): Palauttaa puun T solmujen lukumäärän. Tulos: kokonaisluku isempty(): Testaa, onko puussa T solmuja vai ei. Tulos: totuusarvo elements(): Palauttaa puun T solmuihin talletetut kaikki alkiot luettelona. Tulos: alkioiden luettelo positions(): Palauttaa puun T kaikkien solmujen (paikkojen) luettelon. Tulos: solmujen luettelo 4. luku 168

swap(v,w): Vaihtaa puun T solmujen v ja w alkiot keskenään. Syöte: kaksi solmua replace(v,e): Korvaa solmun v alkion alkiolla e ja palauttaa aiemman alkion. Syöte: solmu ja alkio Tulos: alkio Mitään erityisiä puun päivitysmetodeja ei tässä määritellä, vaan palataan niihin myöhemmin, lähinnä esimerkkien yhteydessä. Tarkastellaan kuitenkin seuraavaksi, miten em. metodit voidaan toteuttaa rajapintana Javalla. 4. luku 169

Puun rajapinta Javalla Puun geneeriset metodit on mainittu koodin 4.1. yhteydessä, ja koodin 4.2. rajapinta laajentaa edellistä. Kyseessä voivat olla mielivaltaisesti valitut oliot, ja SimpleTree perustuu paikan (solmun) abstraktioon. public interface PositionalContainer { // query methods public int size(); // return the size of the container public boolean isempty(); // return whether the container is // empty or not public Enumeration elements(); // return the elements in the // container Koodi 4.1. PositionalContainer-rajapinta. 4. luku 170

public Enumeration positions(); // return the positions in the // container } // update methods public void swap(position v, Position w); // swap elements at v // and w public Object replace(position v, Object e); // replace with e and return the element at v Koodi 4.1. (jatkoa) PositionalContainer-rajapinta. 4. luku 171

public interface SimpleTree extends PositionalContainer { // accessor methods public Position root(); // return the root of the tree public Position parent(position v); // return the parent of v public Enumeration children(position v); // return the children of v // query methods public boolean isinternal(position v); // test whether v is internal public boolean isexternal(position v); // test whether v is // external public boolean isroot(position v); // test whether v is the root of // the tree } Koodi 4.2. SimpleTree-rajapinta 4. luku 172

4.2. Puiden perusalgoritmeja Kuvataan puunkäsittelyalgoritmeja, jotka suorittavat tehtävänsä päästen puuhun käsiksi koodin 4.2. rajapinnalla. Seuravat ajoaikaoletukset tehdään metodeille, jotka toteuttavat rajapinnan, olivatpa ne sitten mistä tahansa luokasta. Geneeriset metodit size(), isempty(), swap(v,w) ja replace(v,e) toimivat ajassa O(1). Metodit root() ja parent(v) toimivat ajassa O(1). Boolen-tyyppiset metodit isinternal(v), isexternal(v) ja isroot(v) toimivat myös ajassa O(1). Metodit elements() ja positions() toimivat ajassa O(n), jossa n on puun solmujen lukumäärä. 4. luku 173

Metodi children(v) toimii ajassa O(c v ), jossa c v on solmun v lasten lukumäärä. Metodien elements() ja children(v) tuloksille metodit hasmoreelements() ja nextelement() toimivat ajassa O(1). Myöhemmin, luvussa 4.4. esitetään tietorakennetoteutukset, jotka täyttävät nämä suoritusaikaoletukset. Sitä ennen käsitellään vielä muutamia perusasioita ja kuinka näitä metodeja sovelletaan puuongelmien ratkaisemisessa. Syvyys ja korkeus Olkoon v puun T solmu. Solmun v syvyys (depth) on sen esivanhempien lukumäärä poislukien solmu itse. Esim. kuvan 4.2. solmun ulkomaat syvyys on 2. Täten juuren syvyys on 0. Solmun syvyys on määriteltävissä rekursiivisesti: 4. luku 174

Jos v on juuri, sen syvyys on 0. Muuten solmun v syvyys on yksi lisättynä solmun v vanhemman syvyydellä. Määritelmän mukaisesti koodin 4.3. algoritmi laskee solmun v syvyyden puussa T. Algoritmin suoritusaika on O(d v ), missä d v viittaa solmun v syvyyteen, sillä algoritmi suorittaa vakioaikaisen rekursiivisen askeleen jokaiselle solmun v esivanhemmalle. Huomaa, että tämän osan (4.2.) Java-esimerkit voivat olla hieman epäyhtenäisiä, joten nämä on syytä lukea ikään kuin pseudokoodina. 4. luku 175

public int depth (SimpleTree T, position v) { } if (T.isRoot(v)) return(0); else return(1+depth(t, T.parent(v))); Koodi 4.3. Metodi depth solmun syvyyden tutkimista varten. 4. luku 176

Solmun v korkeus (height) puussa T rekursiivisesti: määritellään niin ikään Jos v on ulkosolmu eli lehti, sen korkeus on 0. Muuten solmun v korkeus on yksi lisättynä solmun v lapsen maksimikorkeudella. Koko puun korkeus on sama kuin juuren korkeus. Esim. kuvan 4.2. puun korkeus on 4. Puun korkeuden voi mieltää myös sen maksimisyvyytenä jostakin solmusta, joka on sen lehti. Seuraavassa on algoritmi korkeuden laskemista varten. 4. luku 177

public int height1 (SimpleTree T) { // computation of the height of a tree by taking the maximum of the // depths of its external nodes int h = 0; Enumeration nodes_of_t = T.positions(); Koodi 4.4. (alkuosa) Metodi height1 solmun korkeuden laskemista varten. 4. luku 178

} while (nodes_of_t.hasmoreelements()) { Position v = (Position) nodes_of_t.nextelement(); if (T.isExternal(v)) h = Math.max(h,depth(T,v)); } return h; Koodi 4.4. (loppuosa) Metodi height1 solmun korkeuden laskemista varten. Mukana on tyypinmuunnos geneerisestä oliosta Position-olioon sekä metodin max käyttämistä. 4. luku 179

Koodin 4.4. metodi height1 on hyvin yksinkertainen toimintaidealtaan. Se käy läpi kaikki solmut, laskee lehtien korkeudet koodin 4.3. metodin depth avulla ja lopuksi antaa suurimman korkeuden. Algoritmi height1 on melko tehoton. Olkoon d v jälleen solmun v syvyys. Koska d v h +1 n, missä h on puun T korkeus ja n solmujen määrä, voidaan todeta algoritmin depth(v) pahimman tapauksen kompleksisuuden olevan O(h), joka on O(n). Tästä seuraa, että height1 toimii ajassa O( v T d v ), joka on O(nh) eli O(n 2 ) pahimmassa tapauksessa. 4. luku 180

Korkeuden laskeminen voidaan tehdä edellistä tehokkaammin ajassa O(n), kun lasketaan rekursiivisesti puun ja sitten sen lasten alipuiden korkeus. Tästä tulee luokkaa O(c v ) olevaa laskentaa, missä c v on solmun v lasten lukumäärä. Kun kukin iteraatio vaatii aikaa O(1), niin jokaiselle solmulle tarvitaan siis aikaa O(c v ), ja kaikkiaan sitä vaaditaan 4. luku 181

Seuraava lause on monesti hyödyllinen, ja se osoittaa em. puun rekursiivisen korkeuden laskemisen olevan lineaarinen aikakompleksisuudeltaan. Lause 4.1. Olkoon T puu, jossa on n solmua, ja olkoon c v puun T solmun v lasten lukumäärä. Silloin on Perustelu: Lukuunottamatta juurta puun T jokainen solmu on jonkin toisen solmun lapsi, mikä aikaansaa mainitun sarjan summan. 4. luku 182

Puun kulkeminen esijärjestyksessä Puun T kulkeminen (traversal) merkitsee järjestelmällistä tapaa vuorotellen käydä solmuissa eli saada kukin solmu. Kuljettaessa puuta esijärjestyksessä (preorder) käydään ensin juuressa ja sitten tämän alipuissa käymällä lapset rekursiivisesti läpi. Mitä toiminta käynti solmussa merkitsee kulloinkin, riippuu sovelluksesta. Esijärjestys-algoritmin pseudokoodi on kuvattu koodissa 4.5., jossa sitä aluksi kutsutaan käskyllä preorder(t,t.root()). 4. luku 183

Algorithm preorder(t,v): käy solmussa v for solmun v jokaiselle lapselle w do käy rekursiivisesti alipuu juureltaan w kutsuen sitä käskyllä preorder(t,w) Koodi 4.5. Esijärjestys-algoritmi. Puun kulkeminen esijärjestyksessä on hyödyllinen haluttaessa solmut lineaarisessa järjestyksessä, jossa vanhemmat tulevat ennen järjestyksessä käytäviä lapsiaan. 4. luku 184

julkaisu otsikko abstrakti 1. johdanto 2. menetelmät 3. tulokset viitteet 1.1. 1.2. 2.1. 2.2. 2.3. 3.1. 3.2. Kuva 4.7. Puun käynti esijärjestyksessä, jossa jokaisen solmun lapset ovat järjestettyinä vasemmalta oikealle. 4. luku 185

Esim. 4.6. Dokumenttiin liittyvä, kuten esim. 4.3., puun esijärjestyksessä kulkeminen tuottaa perättäisesti koko dokumentin. Puun kulkeminen esijärjestyksessä on tehokas toiminto. Olkoon puussa T solmuja n, ja oletetaan käynnin solmussa vievän aikaa O(1). Tällöin analyysi muistuttaa edellä mainittua tehokasta puun korkeuden laskentaa, joka toimi lineaarisessa ajassa. Esijärjestys-algoritmin ei-rekursiivinen osa vaatii jokaisessa solmussa v aikaa O(c v ), missä c v on solmun v lasten lukumäärä. Lauseen 4.1. mukaan esijärjestys-algoritmin suoritusajaksi tulee O(n). Koodin 4.6. algoritmi kulkee rekursiivisesti puun esijärjestyksessä ja tulostaa kunkin solmun alkion. 4. luku 186

public void preorderprint (SimpleTree T, Position v) { // Preorder traversal of the subtree rooted at node v that prints to // the standard output the elements stored at the nodes in the // order they are visited. It assumes that the elements support // tostring(). System.out.println(T.element(v)); Enumeration children_of_v = T.children(v); while (children_of_v.hasmoreelements()) { Position w = (Position) children_of_v.nextelement(); preorderprint(t,w); // recursive call } } Koodi 4.6. Algoritmi preorderprint. 4. luku 187

Puun kulkeminen esijärjestyksessä on hyödyllistä, kun pitää ratkaista puuongelma, jossa on suoritettava laskentaa solmulle ennen tämän jälkeläisiä. Puun kulkeminen jälkijärjestyksessä Toinen tärkeä puussakulkemisalgoritmi on jälkijärjestys tai loppujärjestys (postorder). Tämä voidaan ymmärtää esijärjestyksen vastakohtana, sillä se käy rekursiivisesti läpi aluksi juuren lasten muodostamat alipuut ja sitten juuren (koodi 4.7). Jos puu on järjestetty, solmun lasten käsittelyn rekursiiviset kutsut tehdään ko. järjestyksen mukaisesti. 4. luku 188

Algorithm postorder(t,v): for solmun v jokaiselle lapselle w do käy rekursiivisesti solmu w juurena alipuu kutsumalla algoritmia postorder(t,w) käy solmussa v Koodi 4.7. Jälkijärjestys-algoritmi. Menetelmän nimi tulee käyntijärjestyksestä, jossa ensin käydään solmun lapsissa ennen itse solmua (kuva 4.8.). Menetelmän analyysi on samankaltainen kuin esijärjestyksellä. Se on O(n), kun yhdessä solmussa käynti vaatii vakioajan. 4. luku 189

julkaisu otsikko abstrakti 1. johdanto 2. menetelmät 3. tulokset viitteet 1.1. 1.2. 2.1. 2.2. 2.3. 3.1. 3.2. Kuva 4.8. Puun kuvasta 4.7. käynti jälkijärjestyksessä. 4. luku 190

Jälkijärjestyksessä kulkemisesta on esimerkkinä rekursiivinen metodi postorderprint koodina 4.8., jossa solmu tulostetaan siinä käytäessä. public void postorderprint (simpletree T, Position v) { } // Postorder traversal of the subtree rooted at node v that prints to // the standard output the elements stored at the nodes in the // order they are visited. Enumeration children_of_v = T.children(v); while (children_of_v.hasmoreelements()) { } Position w = (Position) children_of_v.nextelement(); postorderprint(t,w); // recursive call System.out.println(v.element()); Koodi 4.8. Algoritmi postorderprint. // Assumes elements implement // tostring() 4. luku 191

Jälkijärjestyksessä puun kulkeminen on hyödyllistä ratkaistaessa ongelmia, joissa halutaan laskea solmun jokin ominaisuus, mutta tämä edellyttää, että aiemmin on laskettu solmun lasten vastaava ominaisuus. Luonnollisesti muitakin puiden kulkemisjärjestyksiä on olemassa, kuten myöhemmin binääripuiden yhteydessä esitettävä välijärjestys, mutta esi- ja jälkijärjestykset ovat yksinkertaisia ja usein hyödyllisiä menetelmiä. 4. luku 192

4.3. Binääripuut Erityisen merkittävä puulaji on binääripuut (binary trees). Binääripuu on järjestetty, jossa jokaisella sisäsolmulla on kaksi lasta. Kuten edellä mainittiin, tässä noudatetaan määritelmää, että binääripuu on aito, ts. siinä ei ole solmuja, joilla olisi vain yksi lapsi. Tämä menettelytapa ei kuitenkaan aiheuta mitään hankaluutta yleisyyden kannalta, sillä epäsopivat puut ovat muunnettavissa määritelmän mukaisiksi binääripuiksi. Binääripuilla on paljon sovelluksia, joista nähtiin edellä esim. 4.4. päätöspuista ja esim. 4.5. aritmeettisen lausekkeen esityksestä. 4. luku 193

Binääripuiden ominaisuuksia Binääripuilla on useita mielenkiintoisia ominaisuuksia, kuten seuraava. Lause 4.2. Lehtien lukumäärä binääripuussa T on yksi enemmän kuin sisäsolmujen määrä. Perustelu: Tämä osoitetaan jakamalla solmut lehti- ja sisäsolmuihin. Yksinkertaisimmillaan, kun T käsittää vain juuren, siinä on pelkästään yksi lehti, jolloin lause on tosi. Muussa tapauksessa poistetaan puusta T (mielivaltaisesti valittu) lehti v ja sen vanhempi u, joka on sisäsolmu. Näin poistetaan kerrallaan yksi solmu kumpaakin tyyppiä. Jos solmulla u oli vanhempi w, yhdistetään w solmun v entiseen sisarukseen kuvan 4.9. tapaan. 4. luku 194

w u w z v w z z (a) (b) (c) Kuva 4.9. Operaatio removeaboveexternal(v) poistaa lehden ja sisäsolmun. 4. luku 195

Kyseinen operaatio removeaboveexternal(v) poistaa yhden sisäsolmun ja yhden lehden eli ulkosolmun, mutta puu pysyy edelleen binäärisenä. Toistaen operaatiota päästään lopulta yksittäisen lehden tilanteeseen. Täten on osoitettu, että lehtiä on yksi enemmän kuin sisäsolmuja. Puun T kaikkien samalla syvyydellä d olevien solmujen joukkoa kutsutaan tasoksi (level). Tasolla 0 on juuri, tasolla 1 on enintään kaksi solmua (juuren lapset), tasolla 2 on enintään neljä solmua jne. Yleisesti tasolla d on enintään 2 d solmua (kuva 4.10.). 4. luku 196

taso 0 solmuja 1 1 2 2 4 3 8 Kuva 4.10. Maksimimäärät solmuja binääripuun tasoilla. 4. luku 197

Oheiset ominaisuudet ovat johdettavissa kuvan 4.10. havainnollistamana koskien binääripuun korkeutta ja solmujen määrää. Lause 4.3. Olkoon T aito binääripuu, jossa on n solmua ja h puun korkeus. Silloin puulla T on seuraavat ominaisuudet: 1. Puun T lehtien määrä on vähintään h+1 ja enintään 2 h. 2. Puun T sisäsolmujen määrä on vähintään h ja enintään 2 h -1. 3. Puun T solmujen kokonaismäärä on vähintään 2h+1 ja enintään 2 h+1-1. 4. Puun T korkeus on vähintään log(n+1)-1 ja enintään (n-1)/2 eli log(n+1)-1 h (n-1)/2. Jääkööt näiden perustelut lukijan pohdittaviksi. 4. luku 198

Lauseen 4.3. tärkeä seuraus on se, että n-solmuisen binääripuun minimikorkeus on (log n), jolla on huomattavaa merkitystä puita hyödyntävien algoritmien kompleksisuuksille, kuten myöhemmin nähdään. Binääripuun Java-kielinen rajapinta Binääripuun abstrakti tietotyyppi käsittää yleisen puun metodien lisäksi erityisesti seuraavat (paikka tarkoittaa tässä solmua): leftchild(v): Palauttaa solmun v vasemman lapsen. Virhe esiintyy, mikäli v on lehti. Syöte: paikka Tulos: paikka 4. luku 199

rightchild(v): Palauttaa solmun v oikean lapsen. Virhe esiintyy, mikäli v on lehti. Syöte: paikka Tulos: paikka sibling(v): Palauttaa solmun v sisaruksen. Virhe esiintyy, mikäli v on juuri. Syöte: paikka Tulos: paikka Niin ikään sisällytetään lisäysmetodi: expandexternal(v): Muuttaa lehden v sisäsolmuksi luomalla kaksi uutta lehteä ja asettamalla nämä solmun v lapsiksi. Virhe esiintyy, mikäli v on sisäsolmu. Syöte: paikka 4. luku 200

Myös poistometodi on tarpeen: removeaboveexternal(v): Poistaa lehden v ja tämän vanhemman u sekä sijoittaa v:n sisaruksen u:n paikalle (kuva 4.9.). Operaatio palauttaa solmun u. Virhe esiintyy, mikäli v on sisäsolmu. Syöte: paikka Tulos: alkio Oletetaan käytettävissä olevan binääripuukonstruktori, joka palauttaa yksittäisen lehden ilman alkiota mukanaan. Tästä solmusta lähtien voidaan muodostaa binääripuita metodilla expandexternal. Vastaavasti binääripuita voidaan karsia metodia removeaboveexternal käyttäen ja lopulta päätyä yksittäiseen solmuun. Muuntyyppisiä hyödyllisiä binääripuumetodeja käsitellään 7. luvussa. 4. luku 201

Mallinnetaan binääripuuta abstraktina tietotyyppinä koodin 4.9. Java-rajapinnalla, joka laajentaa edeltävää SimpleTreerajapintaa. Tältä yliluokaltaan se perii metodit. Kun binääripuut ovat järjestettyjä solmun vasen lapsi on järjestyksessä ennen oikeaa. public interface BinaryTree extends SimpleTree { // Simplified interface for a binary tree whose nodes (positions) // store arbitrary elements. // Accessor methods: public Position leftchild(position v); public Position rightchild(position v); public Position sibling(position v); Koodi 4.9. (alku) Rajapinta BinaryTree, joka laajentaa rajapintaa SimpleTree. 4. luku 202

// Update methods: public void expandexternal(position v); public Object removeaboveexternal(position v); } Koodi 4.9. (loppu) Rajapinta BinaryTree. Seuraavat oletukset ovat tehtävissä rajapinnan BinaryTree toteuttavan luokan metodeista. Kaikki rajapinnan SimpleTree yhteydessä esitetyt aikakompleksisuudet pysyvät sellaisenaan. Metodi children(v) toimii binääripuille ajassa O(1), koska jokaisella solmulla on joko ei yhtään tai kaksi lasta. Metodit leftchild(v) ja rightchild(v) toimivat ajassa O(1). Metodit expandexternal(v) ja removeaboveexternal(v) toimivat ajassa O(1). 4. luku 203

Binääripuussa kulkeminen Puiden soveltaminen merkitsee hyvin usein niiden läpikäyntiä. Seuraavaksi tarkastellaan mainittua asiaa hyödyntäen annettua rajapintaa BinaryTree. Binääripuun kulkeminen esijärjestyksessä Mikä tahansa binääripuu voidaan mieltää myös yleisenä puuna, joten yleisen puun esijärjestys toimii yhtä hyvin binääripuulle. Tällöin sitä (koodi 4.10.) voidaan jopa yksinkertaistaa, sillä binääripuu on rajoitetumpi kuin yleinen muoto. Jälleen puun kulkemisella esijärjestyksessä on lukuisia sovelluksia. Esimerkkinä voidaan kloonata, kopioida, binääripuu T samanlaiseksi puuksi T aloittaen yhden lehden käsittävästä puusta T ja käyden puuta T rekursiivisesti läpi (koodi 4.11.). 4. luku 204

Algorithm binarypreorder(t,v): käy solmussa v (ja tee siellä tarvittava laskenta) if v on sisäsolmu then binarypreorder(t,t.leftchild(v)) binarypreorder(t,t.rightchild(v)) {käy rekursiivisesti vasemmassa alipuussa} {käy rekursiivisesti oikeassa alipuussa} Koodi 4.10. Algoritmi binarypreorder. Kun solmussa käyminen vaatii ajan O(1), binääripuun kopioiminen tarvitsee vain ajan O(n). 4. luku 205

Algorithm clone(t,t,v,v ): Input: Binääripuu T, joka sisältää solmun v, ja binääripuu T, joka sisältää lehtisolmun v. Output: Lisätty binääripuu T niin, että v on alipuun juurena ja alipuu on kopio puusta T, jonka juurena v on. if v on sisäsolmu then expandexternal(v ) v.element v.element() clone(t,t,t.leftchild(v),t.leftchild(v )) clone(t,t,t.rightchild(v),t.rightchild(v )) Koodi 4.11. Algoritmi clone. 4. luku 206

Binääripuun kulkeminen jälkijärjestyksessä Jälkijärjestys toimii binääripuilla samantapaisesti kuin edellä. Algoritmi on annettu koodina 4.12. Algorithm binarypostorder(t,v): if v on sisäsolmu then binarypostorder(t,t.leftchild(v)) binarypostorder(t,t.rightchild(v)) käy solmussa v (ja tee siellä tarvittava laskenta) Koodi 4.12. Algoritmi binarypostorder. 4. luku 207

Jälkijärjestyskäsittely sopii hyvin mm. aritmeettisten binääristen operaatioiden evaluointiin ja muihin alhaalta-ylös- (bottom-up) eli kokoaviin evaluaatio-ongelmiin. Binääripuun käsittely jälkijärjestyksessä on tehtävissä ajassa O(n). Binääripuun kulkeminen välijärjestyksessä Binääripuut voidaan kulkea kolmannellakin tavalla, välijärjestyksessä (inorder). Tällöin solmussa käydään vasemman ja oikean alipuun rekursiivisten kutsujen välissä (koodi 4.13.). 4. luku 208

Algorithm inorder(t,v): if v on sisäsolmu then inorder(t,t.leftchild(v)) {kulje vasen alipuu rekursiivisesti} käy solmussa v (ja tee siellä tarvittava laskenta) if v on sisäsolmu then inorder(t,t.rightchild(v)) {kulje oikea alipuu rekursiivisesti} Koodi 4.13. Binääripuun kulkeminen välijärjestyksessä. Binääripuun T kulkeminen välijärjestyksessä on nähtävissä solmujen läpikäyntinä vasemmalta oikealle. Jokaiselle solmulle v vasta kaikkien sen vasemman alipuun solmujen käynnin jälkeen käydään v:ssä ja vasta tämän jälkeen sen oikean alipuun solmuissa (kuva 4.11). 4. luku 209

/ + + 6 + 3 2 3 3 1 9 5 7 4 Kuva 4.11. Binääripuun kulkeminen välijärjestyksessä. 4. luku 210

Myös välijärjestyskulkemisella on lukuisia sovelluksia. Yksi tärkeimmistä on järjestetyn sekvenssin alkioiden tallettaminen puuhun, joka määrittelee rakenteen nimeltä binäärihakupuu (binary search tree) (kuva 4.12.). Siinä jokainen solmu v tallettaa alkion e tavalla, jossa v:n vasempaan alipuuhun talletetut alkiot ovat pienempiä tai yhtä suuria kuin e ja oikeaan alipuuhun talletetut tätä suurempia. Kuljettaessa välijärjestyksessä alkiot käydään ne läpi ei-vähenevässä järjestyksessä. Binäärinen hakupuu voidaan mieltää binääriseksi päätöspuuksi, joka tukee hakua ja jossa päätös tehdään sisäsolmussa kysymykselle, onko solmun alkio joko pienempi tai yhtä suuri tai suurempi kuin haettava alkio. 4. luku 211

Binäärihakupuuta käytetään paikallistamaan määrätynarvoinen alkio kulkien puuta T alaspäin. Kussakin sisäsolmussa verrataan sen arvoa haettavaan alkioon (hakuavaimeen). Mikäli vastaus on pienempi, jatketaan hakua vasemmassa alipuussa. Jos vastaus on yhtä suuri, alkio on löydetty. Mikäli se on suurempi, jatketaan hakua oikeassa alipuussa. Jos törmätään lehteen alkiota löytämättä, haku päättyy. Tärkeä havainto on, että haun suoritusaika on suhteessa puun T korkeuteen. Kuva 4.12. esittää esimerkin binäärihausta, mutta tätä tarkempi käsittely annetaan myöhemmin, luvussa 6.3. Puiden kulkemisalgoritmien tehokkuus perustuu rekursiivisyyteen. Rekursion käyttö ei kuitenkaan ole välttämätöntä, vaan voidaan käyttää (eksplisiittistä) pinoa, johon talletetaan myöhemmin tarvittavia esivanhempisolmuja matkan varrelta näihin myöhemmin palaamista varten. Tämä ei-rekursiivinenkin käsittely voidaan suorittaa lineaarisessa ajassa ja samalla säästää hieman tarvittavaa muistitilaa, jota rekursiokutsujen hallinta vaatii ohjelmointiympäristöltä. 4. luku 212

58 31 90 25 42 62 12 36 75 Kuva 4.12. Kokonaislukuja sisältävä binäärihakupuu. Kiinteät paksut viivat (keskellä) kuvaavat luvun 36 onnistuneen haun ja katkoviivat luvun 70 epäonnistuneen haun. 4. luku 213

Binääripuun Eulerin matkan kulkeminen Edellä esitetyissä puunkulkemismenetelmissä käytiin kussakin solmussa tarkalleen vain kerran. Nämä menetelmät voidaan yhdistää yhdeksi menetelmäksi sallimalla yhtä useampi käynti solmussa puun kulkemisen aikana. Tällainen menetelmä on Eulerin matkan kulkeminen (Euler tour traversal). Siinä saadaan puun yleisen kulkemisen esitys. Intuitiivisesti esitettynä kysymys on binääripuun kulkemisesta ympärikävelynä, jossa lähdetään juuresta ja kuljetaan tämän vasempaan lapseen pitämällä kaaret (edge, arc) kulkusuunnasta katsoen vasemmalla puolella (kuva 4.13.). Puun T jokaisessa solmussa v käydään kolmesti: vasemmalta (ennen solmun v vasempaan alipuuhun menoa), alhaalta (solmun v vasemman ja oikean alipuun välissä) ja oikealta (solmun v oikean alipuun käynnin jälkeen). 4. luku 214

/ + + 6 + 3 2 3 3 1 9 5 7 4 Kuva 4.13. Eulerin matka binääripuussa. 4. luku 215

Solmun v ollessa lehti kaikki kolme käyntiä tapahtuvat itse asiassa samalla kertaa. Menetelmä on esitetty algoritmina koodissa 4.14. Algorithm eulertour(t,v): käy solmussa v vasemmalta if v on sisäsolmu then käy rekursiivisesti solmun v vasemmassa alipuussa käyttäen kutsua eulertour(t,t.leftchild(v)) käy solmussa v alhaaltapäin if v on sisäsolmu then käy rekursiivisesti solmun v oikeassa alipuussa käyttäen kutsua eulertour(t,t.rightchild(v)) käy solmussa v oikealta Koodi 4.14. Algoritmi eulertour. 4. luku 216

Kulkeminen esijärjestyksessä muistuttaa Eulerin matkaa siinä mielessä, että solmuun liittyy käynti tultaessa solmuun sen vasemmalta puolelta. Vastaavasti väli- ja jälkijärjestyksille solmussa käydään tultaessa alhaaltapäin tai oikealta. Esi-, jälki- ja välijärjestys-algoritmien suoritusajat olivat O(n), kun käynti solmussa vaati vakioajan. Niin on Eulerin matkan tapauksessakin, suoritusaika O(n). Eulerin matkalla on erilaisia sovelluksia, joihin ei tässä puututa. Kuvatusta yleisluonteisesta Eulerin matkasta voidaan muodostaa myös muita kulkemismenetelmiä kuin em. kolme perusmenetelmää. 4. luku 217

4.4. Puutietorakenteiden toteuttaminen Seuraavaksi tarkastellaan puiden konkreettista esittämistä tietorakenteina sekä puun ja binääripuun abstrakteja tietotyyppejä. Binääripuiden sekvenssipohjainen rakenne Binääripuun T yksinkertainen toteutus perustuu sen solmujen määrättyyn numerointiin. Olkoon p(v) kuhunkin solmuun v liitetty kokonaisluku määriteltynä seuraavasti (kuva 4.14.): Jos v on puun T juuri, niin p(v) = 1. Jos v on solmun u vasen lapsi, niin p(v)=2p(u). Jos v on solmun u oikea lapsi, niin p(v)=2p(u)+1. 4. luku 218

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 (a) Kuva 4.14. Binääripuun tasojen numerointi: (a) yleinen kaavio. 4. luku 219

1 2 3 / + 4 5 6 + 6 7 8 9 10 11 12 13 + 3 2 3 16 17 20 21 26 27 3 1 9 5 7 4 Kuva 4.14. (jatkoa) Binääripuun tasojen numerointi: (b) esimerkki. 4. luku 220

Funktio p antaa solmujen järjestysnumeroinnin, kun se järjestää solmut puussa tasoittain kasvavaan järjestykseen vasemmalta oikealle (joskus voidaan hypätä yli joitakin numeroita, so. tyhjät alkiot). Funktio p muodostaa binääripuun esityksen sekvenssin S avulla, jolloin T:n solmu v liitetään S:n alkion astetta p(v) (ks. kuvaa 4.15.). Tavallisesti sekvenssi tässä tapauksessa toteutetaan taulukkona, jonka käyttö on nopeaa ja yksinkertaista. Sille saadaan tehokkaat toteutukset metodeille root, parent, leftchild, rightchild, isinternal, isexternal ja isroot muutamin yksinkertaisin aritmeettisin laskutoimituksin solmujen luvuilla p. Yksityiskohtiin menemättä (harjoitustehtävä) todetaan jokaisen mainituista metodeista toimivan ajassa O(1). 4. luku 221

1 / T 2 + 3 4 5 + 3 6 2 7 8 9 12 13 3 1 9 5 S 0 1 2 3 4 5 6 7 8 9 10 11 12 13 Kuva 4.15. Binääripuuesitys sekvenssin avulla. 4. luku 222

Olkoon n puun T solmujen lukumäärä ja N arvon p(v) maksimi puussa T. Kun sekvenssi on toteutettu em. tavalla, taulukon koko on vähintään n+1 ja enintään N (alkio astetta 0 ei liity mihinkään solmuun). Sekvenssi voi sisältää paljon tyhjiä alkioita, jotka eivät liity mihinkään solmuun. Pahimmassa tapauksessa on N = 2 (n+1)/2-1 (perustelu harjoitustehtävänä). Myöhemmin, luvussa 6.3., esitetään keko- eli kasarakenne, jossa on N = n+1. Tilaa hukkaavasta piirteestään huolimatta sekvenssi on tehokas rakenne binääripuiden tapauksessa, mutta ei enää monihaaraisen yleisen puun tilanteessa. Taulukossa 4.1. on yhteenveto binääripuutoteutuksen metodien suoritusajoista sekvenssiä käytettäessä. Sekvenssi on tässä tehokas, mutta korkeille puille muistitilan käyttö on tehotonta. 4. luku 223

Taulukko 4.1. Binääripuun T metodien suoritusajat käytettäessä taulukolla toteutettua sekvenssiä. Solmujen määrä on n ja sekvenssin koko N. Metodeihin elements(), positions(), ja children(v) liittyvät hasmoreelements() ja nextelement() toimivat ajassa O(1). Tilavaatimus on O(N), joka on O(2 (n+1)/2 ) pahimmassa tapauksessa. Metodilla removeaboveexternal(v) on yleisessä tapauksessa O(n), mutta solmun v molempien lapsien ollessa lehtiä, kuten yleensä, se on O(1). 4. luku 224

Binääripuiden linkitetty rakenne Linkitetty rakenne (linked structure) on luonnollinen tapa toteuttaa binääripuu T. Tällöin jokainen solmu v esitetään oliolla, jolla on viittaukset solmuun v talletettuun alkioon sekä solmun v lapsiin ja vanhempaan liittyviin olioihin (ks. kuva 4.16.). Solmu v on esitettävissä olion avulla, jolla on muuttujat element, left, right ja parent. Nämä viittaavat solmuun v tallettettuun alkioon, tämän vanhempaan sekä vasempaan ja oikeaan lapseen. Tarvitaan myös metodit, joilla muuttujien arvot saadaan ja asetetaan. 4. luku 225

vanhempi juuri solmu v 5 koko vasen alkio oikea (a) Baltimore Chicago New York Providence Seattle (b) Kuva 4.16. Binääripuutoteutus linkitettynä rakenteena: (a) solmun v olio ja (b) viiden solmun binääripuu kokonaisuudessaan. 4. luku 226

Seuraavassa on lueteltu normaalisti tarvitut metodit, joiden nimi kertoo tehtävän. Metodit size() ja isempty() toimivat ajassa O(1). Metodissa swap(v,w) yksinkertaisesti vaihdetaan alkioiden v ja w viittaukset keskenään. Se toimii ajassa O(1). Myös metodi replace(v,e) on toteutettavissa toimivaksi ajassa O(1). Käyttäen sekvenssiä ja paikkaa siinä operaatiot elements(), positions() ja children() ovat toteutettavissa. Niissä käytettävät apumetodit hasmoreelements() ja nextelement() toimivat ajassa O(1). Metodi positions() voidaan toteuttaa kulkemalla binääripuu läpi (esi-, väli- tai jälkijärjestyksessä). Käytäessä solmussa v lisätään viittaus siihen sekvenssin loppuun. Metodi elements() on samankaltainen. Tällöin nämä toimivat ajassa O(n). 4. luku 227

Jokaista puun T solmua varten on olio. Puuta itseään varten on oma olionsa. Nämä oliot vaativat vakiomäärän tilaa. Niinpä tarvittava kokonaistila on c 1 n + c 2, missä c 1 ja c 2 ovat joitakin positiivisia vakioita, ts. O(n). Taulukossa 4.2. on yhteenveto binääripuun metodien suoritusaikavaatimuksista. Taulukko 4.2. Binääripuun (n solmua) metodien suoritusajat linkitettyä rakennetta käytettäessä. Muistitilavaatimus on O(n). 4. luku 228

Yleisten puiden linkitetty rakenne Linkitetyn rakenteen käyttö on mahdollista laajentaa binääripuista yleisiin puihin. Kun ei ole rajoitettu lasten määrää yleisen puun solmuissa, käytetään säiliötä (container, esim. sekvenssinä) solmun v lasten tallettamiseen muuttujien sijasta. Tätä esittää kuva 4.17. Käytettäessä säiliötä lasten tallettamiseen metodi children(v) voidaan toteuttaa yksinkertaisesti käyttäen apuna metodia elements(). 4. luku 229

vanhempi alkio New York lasten säiliö (a) Baltimore Chicago Providence Seattle Kuva 4.17. Yleisen puun linkitetty rakenne: (a) solmuun liitetty olio ja (b) osa tietorakennetta, jossa on solmu lapsineen. (b) 4. luku 230

Taulukko 4.3. esittää linkitetyn rakenteen toteutusten suorituskyvyn. Operaatioiden analyysi jääköön lukijalle. Taulukko 4.3. Yleisen puun (n solmua ja c v solmun v lapset) metodien suoritusajat käytettäessä linkitettyä rakennetta ja tilavaatimuksen ollessa O(n). 4. luku 231

Yleisten puiden esittäminen binääripuiden avulla Yleisen puun T vaihtoehtoinen esitystapa edellä esitetylle on muuntaa se binääripuuksi T (kuva 4.18.). Puu T on järjestetty tai mielivaltaisessa järjestyksessä. Muunnos on seuraava: Puun T jokaisella solmulla u on olemassa puun T sisäsolmu u, joka liittyy solmuun u. Jos puun T solmu u on lehti, jolla ei ole sitä seuraavia sisaruksia, niin puun T solmun u lapset ovat lehtiä. Jos puun T solmu u on sisäsolmu ja v on u:n ensimmäinen lapsi, niin v on u :n vasen lapsi puussa T. Jos solmulla v on sisarus w välittömästi seuraavana, niin w on v :n oikea lapsi T :ssa. Puun T lehdet eivät liity puun T solmuihin, vaan ovat ainoastaan paikanpitäjiä. 4. luku 232

A A B C D E B C E F G (a) F D G Kuva 4.18. Yleisen puun esitys binääripuun avulla: (a) puu T ja (b) edelliseen liittyvä puu T. Katkoviivat yhdistävät T :n solmut, jotka liittyvät T:n sisarussolmuihin. (b) 4. luku 233

On helppoa ylläpitää puiden T ja T vastaavuus sekä ilmaista operaatiot T:ssä vastaavien operaatioiden suhteen T :ssa. Voidaan ajatella muunnos puusta T puuhun T niin, että otetaan kukin joukko {v 1, v 2,, v k } sisaruksia puusta T vanhempanaan v ja korvataan se oikeanpuoleisten lapsien ketjulla, jonka juuri on solmussa v 1. Tästä puolestaan tulee solmun v vasen lapsi. Taulukossa 4.4. on yleisen puun metodien suoritusajat käytettäessä kuvatulla tavalla binääripuuta sen toteutuksena. 4. luku 234

Taulukko 4.4. Binääripuun (linkitetty rakenne) avulla toteutetun puun metodien suoritusajat, missä puun solmujen määrä on n, solmun v lasten määrä c v ja sisarusten määrä s v. Metodien elements(), positions() ja children(v) käyttämät metodit hasmoreelements() ja nextelement() vaativat ajan O(1). Tilavaatimus on O(n). 4. luku 235