B + -puut Kerttu Pollari-Malmi Tämä monista on alunperin kirjoitettu sksn 2005 kurssille osittain Luukkaisen ja Nkäsen vanhojen luentokalvojen pohjalta. Maaliskuussa 2010 pseudokoodiesits on muutettu vastaamaan Cormenin kolmannen painoksen pseudokoodia. 1 Yleistä B-puusta Binäärihakupuut toimivat hvin keskusmuistissa Jos hakemisto on levmuistissa, binäärihakupuu ei kuitenkaan ole hvä ratkaisu. Tämä johtuu siitä, että tiedon lukeminen levltä on paljon hitaampaa kuin sen käsitteleminen keskusmuistissa. Lisäksi suuri osa levhakuun kuluvasta ajasta kuluu oikean levn kohdan hakemiseen. Kerralla haettava tietomäärä vaikuttaa hakuaikaan vähän, jos haetaan korkeintaan muutamia kilotavuja. Sopiva hakupuurakenne levmuistiin on B-puu. Siinä pritään puun korkeus ja levhakujen määrä pitämään pienenä sillä, että jokaisella solmulla voi olla paljon (kmmeniä tai satoja) lapsia. Kätännössä levmuistissa olevan B-puun korkeus on leensä 2 tai 3. Tällä kurssilla käsiteltävät B-puun versiot ovat vähän erilaisia kuin Cormenin kirjassa esitett, joissa avaimia on tallennettu puun kaikkiin solmuihin. Tällä kurssilla käsitellään B-puun versioita, joissa kaikki rakenteen avaimet (joukon alkiot) ovat lehtisolmuissa. Puun lemmissä solmuissa (sisäsolmuissa) on viitta-arvoja. Ne ovat samantppisiä arvoja kuin itse avaimet, mutta eivät itse joukon alkioita. Niitä kätetään vain ohjaamaan avaimen hakua ja muita operaatiota lempänä puussa. Tällaisia B-puita kutsutaan B + puiksi, joissakin lähteissä mös B -puiksi. Kurssilla käsitellään niitä Cormenin puiden sijasta, koska Kätännössä B + -puita kätetään paljon useammin kuin tavallisia B-puita. Operaatiot B + -puussa ovat vähän ksinkertaisempia kuin tavallisessa B-puussa. 2 B + -puun rakenne B + -puu T koostuu solmuista. Yksi solmuista on juurisolmu T.root. Jos solmu on sisäsolmu, sillä on seuraavat kentät: 1
.n solmuun tällä hetkellä tallennettujen viitta-arvojen lukumäärä. Solmuun tallennetut viitta-arvot järjestksessä.router 1 <.router 2 <... <.router.n.leaf, jonka arvo on FALSE kertomassa, että ei ole lehtisolmu.n+1 viitettä.c 1,.c 2,.c 3,...,.c.n+1 solmun lapsisolmuihin. Jos solmu on lehtisolmu, sillä on seuraavat kentät:. solmuun tällä hetkellä tallennettujen avainarvojen lukumäärä. Solmuun tallennetut avainarvot järjestksessä.ke 1 <.ke 2 <... <.ke.n.leaf, jonka arvo on TRUE kertomassa, että on lehtisolmu Kun tarkastellaan sisäsolmua, niin sen viitteille.c 1,.c 2,.c 3,...,.c.n+1 pätee seuraava ehto: k 1.router 1 < k 2.router 2 < k 3... < k.n.router.n < k.n+1 missä k i on mikä tahansa viitteen.c i päässä olevassa alipuussa oleva avain tai viitta-arvo. Sisäsolmun kaksi peräkkäistä viitta-arvoa antavat siis ala- ja lärajan sille, kuinka suuria avaimia niiden välissä olevan viitteen päässä olevassa alipuussa voi olla. Esimerkki sisäsolmusta, jossa on 5 viitta-arvoa. leaf false n 5 10 18 45 66 98 Yleensä solmua piirrettäessä kenttien.n ja.leaf arvoja ei merkitä: 10 18 45 66 98 Lehtisolmut sisältävät n ja leaf -kenttien lisäksi vain avaimia. (Kätännössä avaimen htedessä voi olla alkion muiden kenttien arvoja tai viite paikkaan, johon muiden kenttien arvot on tallennettu. Niitä ei ole mukana kuvissa ksinkertaisuuden vuoksi.) leaf n true 8 19 21 23 24 27 29 44 45
Yleensä lehtisolmuakaan piirrettäessä kenttien n ja leaf arvoja ei merkitä: 19 21 23 24 27 29 44 45 B + -puun solmun koko valitaan leensä siten, että solmun koko (tavuina) on kätetn levmuistin levlohkon koko tai monikerta. Näin kokonainen solmu voidaan hakea levltä kätännössä lähes samassa ajassa kuin ksi binäärihakupuun solmu (jos se olisi keskusmuistin sijasta levmuistissa). Tpillisesti hdessä solmussa on kmmeniä tai satoja viitta-arvoja tai avaimia. Tällaisen solmun käsitteln menee enemmän aikaa kuin hden pienen solmun käsitteln, mutta solmun käsittelaika on kuitenkin vain pieni osa siitä ajasta, joka kuluu solmun hakemiseen kovalevltä. Jos B + -puussa jokaisella solmulla on 100 lasta ja puun korkeus on 2, mahtuu puuhun miljoona avainta. Mikä tahansa näistä avaimista voidaan saavuttaa sillä, että kovalevltä haetaan hteensä 3 solmua. Esimerkki B + -puusta (piirustusteknisistä sistä solmun koko on paljon pienempi kuin mitä se on kätännön B + -puissa): 13 29 79 5 19 47 67 85 2 5 6 7 11 12 14 19 20 23 31 41 47 50 53 61 63 68 73 75 76 80 83 84 87 88 3 B + -puun tasapainoehdot Jos jokaisella B + -puun solmulla on vain vähän lapsia, B + -puusta tulee korkea ja kukin operaatio vaatii paljon levhakuja. Sama ongelma on silloin, jos joku polku B + -puun juuresta lehteen on paljon pitempi kuin polut juuresta muihin lehtiin. Kätännössä ei kuitenkaan kannata vaatia sitä, että B + -puun jokainen solmu olisi aivan tännä. Tällaisen ehdon lläpitäminen vaatisi niin paljon limääräistä tötä, että operaatioiden tehokkuus kärsisi. B + -puun tasapainoehdot ovat seuraavat: Jokainen polku juuresta lehteen on htä pitkä. Jokainen solmu juurisolmua lukuunottamatta on vähintään puolillaan.
Jälkimmäinen tasapainoehto voidaan esittää tarkemmin seuraavasti: Merkitään s():llä solmun lasten lukumäärää, jos on sisäsolmu, ja solmun avainten lukumäärää, jos on lehtisolmu. Olkoon t 2 kokonaislukuvakio, joka on määrätt puuta luodessa. Tällöin B + - puun jokaiselle solmulle pätee 1 s() 2t, jos on puun ainoa solmu. 2 s() 2t, jos on puun juuri ja puussa on muitakin solmuja. t s() 2t, muuten. Vakio t siis määrät sen mukaan, mikä on puun solmun maksimikoko: Solmulla on korkeintaan 2t lasta tai avainta ja solmun lasten tai avainten minimimäärä on t, jos solmu ei ole juurisolmu. Kun B + -puu toteuttaa nämä tasapainoehdot, voidaan osoittaa, että B + -puun korkeudelle h pätee h log t n kun puussa on n avainta. Tulos saadaan laskemalla solmujen maksimäärä korkeudella 0, mistä saadaan solmujen maksimimäärä korkeudella 1 (koska tiedetään, että jokasella solmulla tät olla vähintään t lasta) ja niin edelleen. Puun korkeudelle h pätee, että solmujen maksimimäärä korkeudella h on korkeintaan ksi. Tästä voidaan johtaa ehto puun maksmikorkeudelle. Siis mös B + -puu on tasapainoinen. Logaritmin kantalukuna on kuitenkin t eikä 2 kuten binäärihakupuissa. B + -puuta ei tasapainoteta kierroilla, vaan muuttamalla solmun lasten tai avainten määrää tasapainoehdoissa annetuissa rajoissa. Jos lisäs tai poisto johtaisi tasapainoehdon rikkoutumiseen jossain solmussa, solmu voidaan halkaista tai hdistää sisarukseen tai solmun ja sen sisaruksen sisältöä voidaan siirtää näiden kahden solmun välillä niin, että tasapainoehdot saadaan voimaan. 4 Haku B + -puussa Haku aloittaa juurisolmusta ja etenee jokaisessa solmussa seuraavasti: Jos ei ole lehtisolmu, etsitään solmun ensimmäinen viitta-arvo.router i joka on suurempi tai htäsuuri kuin haettava avain k. Tämän jälkeen jatketaan hakua solmusta, johon viite.c i viittaa. Jos kaikki solmun viitta-arvot ovat pienempiä kuin haettava avain k, jatketaan hakua solmun viimeisen viitteen päässä olevasta solmusta. Jos on lehtisolmu, tutkitaan, onko haettava avain tässä lehdessä.
Esimerkki hakuoperaatiosta (allekkain olevat kuvat kuvaavat tilannetta haun eri vaiheissa) Hae 23: 13 29 79 5 19 47 67 85 2 5 6 7 11 12 14 19 20 23 31 41 47 50 53 61 63 68 73 75 76 80 83 84 87 88 Hae 23: 13 29 79 5 19 47 67 85 2 5 6 7 11 12 14 19 20 23 31 41 47 50 53 61 63 68 73 75 76 80 83 84 87 88 Hae 23: 13 29 79 5 19 47 67 85 2 5 6 7 11 12 14 19 20 23 31 41 47 50 53 61 63 68 73 75 76 80 83 84 87 88 BTreeSearch(T,k) 1 = T.root 2 while not.leaf 3 i = 1 4 while i.n and k >.router i 5 i = i+1 6 =.c i 7 DiskRead() 8 i = 1 // ollaan lehtisolmussa 9 while i.n and k >.ke i 10 i = i+1 11 if i.n and k =.ke i 12 return (, i ) 13 else return NIL
B + -puualgoritmeissa kannattaa merkitä levlohkojen luvut keskusmuistiin ja kirjoitukset levlle, koska ne vievät leensä paljon enemmän aikaa kuin kaikki algoritmin keskusmuistissa suoritettavat operaatiot. Yllä esitetssä hakualgoritmissa on oletettu, että B + -puun juuri on valmiiksi keskusmuistissa (näin on usein kätännössä). Jos juurisolmu ei ole keskusmuistissa, pitää algoritmin alkuun lisätä sen lukeminen levltä. 4.1 Hakuoperaation aikavaatimus Hakuoperaation aikana luetaan levltä keskusmuistiin h solmua, missä h on puun korkeus. Aikaisemmin todettiin, että B + -puilla h = O(log t n), missä n on puuhun tallennettujen avaimien määrä. Jokaisessa solmussa suoritetaan keskusmuistissa peräkkäishaku, joka vaatii ajan O(t). Tällöin hakuoperaation kokonaisaikavaatimus on O(t log t n). Jos solmussa suoritetaan peräkkäishaun sijaan binäärihaku, aikavaatimus saadaan hieman paremmaksi O(log 2 t log t n). Kätännössä kuitenkin levhakuihin kuluva aika määrää haun suoritusajan, sillä levhakuun kuluva aika on selvästi suurempi kuin hdessä solmussa keskusmuistissa suoritettavaan peräkkäishakuun kuluva aika. Usein B + -puuoperaatioiden tehokkuudesta puhuttaessa lasketaankin vain levoperaatioiden määrää, eikä puhuta varsinaisesta aikavaatimuksesta. 5 Lisäs B + -puuhun Avaimen lisäs B + -puuhun aloitetaan etsimällä se lehtisolmu, johon lisättävä avain kuuluu. Tämä tehdään kuten hakuoperaatio. Jos lödetssä lehtisolmussa on tilaa, avain lisätään solmuun eikä muita toimenpiteitä tarvita. Jos solmussa ei ole tilaa lisättävälle avaimelle, se pitää halkaista: Varataan tilaa uudelle solmulle z. Solmun ensimmäiset t avainta jätetään solmuun. Solmun viimeiset t avainta siirretään uuteen solmuun z. Lisättävä avain lisätään joko solmuun tai z. Solmu määrät sen mukaan, kumpaan solmuun uusi avain kuuluu suuruusjärjestksen mukaisesti. Jotta möhemmät operaatiot lötäisivät solmuun z siirrett avaimet, pitää :n ja z:n hteiseen vanhempaan lisätä viite z:taan ja sopiva viitta-arvo :n ja z:n viitteiden väliin. Viitta-arvoksi sopii suurin solmun avainarvoista. Jos solmuun ei mahdu uutta viitettä ja viitta-arvoa, pitää sekin halkaista. Pahimmillaan halkaisut jatkuvat juurisolmuun saakka. Esimerkki lehtisolmun halkaisusta:
Lisää 59: 47 47 31 41 47 50 53 61 63 31 41 47 50 53 61 63 z 47 47 59 z 31 41 47 50 53 59 61 63 z 31 41 47 50 53 59 61 63 Sisäsolmussa on ksi viitta-arvo vähemmän kuin viitteitä. Sen vuoksi sisäsolmun halkaisussa halkaistavan solmun keskimmäiselle viitta-arvolle ei ole paikkaa kummassakaan solmussa. Se siirt halkaistavan sisäsolmun vanhempaan erottamaan halkaisun tuloksena sntneitä kahta solmua. Alla esimerkki tilanteesta, jossa solmuun halutaan sijoittaa ksi uusi viite ja viitta-arvo 59. (Viitta-arvo 59 lisätään halkaisun tuloksena sntneistä solmuista vasempaan, koska 59 on suuruusjärjestksessä ennen halkaisukohdassa ollutta viitta-arvoa 67. Jos täteen solmuun olisi lisätt suurempi viitta-arvo kuin 67, olisi se lisätt oikeanpuoleiseen solmuun.) 29 79 29 67 79 47 67 47 29 67 79 47 59 Jos halkaistavan sisäsolmun vanhempi on tännä, pitää sekin halkaista, jotta siihen mahtuisi uusi viite ja viitta-arvo. Pahimmillaan halkaisut voi jatkua juureen asti. Alla esimerkki tilanteesta, jossa arvon 59 lisääminen lehteen saa aikaan kolmen solmun halkaisun. (Kuvassa on vain osa B + -puusta. Jokaisen viitteen päässä on joku solmu, jolla voi olla mös lapsia niin, että polku juuresta kaikkiin B + -puun lehtisolmuihin on htä pitkä.)
29 Lisää 59 13 29 79 13 67 79 47 67 47 59 50 53 61 63 50 53 59 61 63 Lisäsalgoritmin ajantarve on O(t log t n), missä kerroin t tulee avainten ja viitteiden tutkimisesta siirtelstä keskusmuistissa. Kätännössä suoritusajan määrää kuitenkin levhakujen määrä, joka on O(log t n) Esitetssä algoritmissa tehdään ensin lisäs. Sen jälkeen mennään takaisin löspäin ja tehdään tarvittavat solmujen halkaisut. Voitaisiin menetellä mös päinvastoin: jo matkalla juuresta lehteen halkaistaan varmuuden vuoksi kohdatut tädet solmut. Tällöin uusi avain mahtuu aina lehteen, eikä enää tarvitse palata taaksepäin. Näin polku juuresta lehtisolmuun pitää kulkea vain hteen kertaan, mutta toisaalta solmujen halkaisuja voidaan joutua tekemään turhaan. 6 Avaimen poisto Avaimen poisto aloitetaan hakemalla se lehtisolmu, joka sisältää poistettavan avaimen. Vaikka sama arvo olisi mös viitta-arvona lempänä puussa, riittää lehdessä olevan avaimen poisto. Ylempänä olevaa viitta-arvoa tarvitaan poiston jälkeenkin ohjaamaan poistettavan avaimen kanssa samassa lehtisolmussa tai alipuussa sijaitseviin avaimiin kohdistuvia hakuja ja muita operaatioita. Koska ksi solmu sisältää useita avaimia, ei itse solmua tarvitse poistaa. Avain vain poistetaan solmusta. Tarvittaessa solmussa olevia muita avaimia siirretään solmun sisällä niin, että ne ovat suuruusjärjestksen mukaisilla paikoilla poiston jälkeenkin. Jos lehtisolmuun jää poiston jälkeen vähintään t avainta, ei muita toimenpiteitä tarvita. Jos avaimien määrä solmussa olisi poiston jälkeen t 1, suoritetaan tasapainotus. Tasapainotukseen otetaan mukaan liian vajaaksi jääneen solmun sisarus z. Solmussa on siis t 1 avainta. Jos solmussa z on korkeintaan t + 1 avainta, mahtuvat :n ja z:n avaimet hteen solmuun. Tällöin solmun z avaimet siirretään sen sisarukseen. Samalla poistetaan solmujen hteisestä vanhemmasta solmuun z viittaava viite sekä :n ja z:n viitteiden välissä oleva viitta-arvo.
Poista 53: 47 67 47 67 47 50 53 68 69 z 50 68 69 z 50 68 69 Jos vanhemmalle jää alle t lasta solmujen ja z hdistämisen jälkeen, pitää tasapainotusta jatkaa solmusta, joka on siis sisäsolmu. Jos sisäsolmu hdistetään sisaruksensa kanssa, niin näitä kahta solmua vanhemmassa erottava viitta-arvo putoaa hdistettn solmuun. Pahimmassa tapauksessa hdistämiset jatkuvat juureen saakka. Jos juurelle jää vain ksi lapsi, niin se poistetaan. Seuraavassa esimerkissä lähdetään suorittamaan tasapainotusta sen jälkeen, kun kuvassa vasemmalla olevasta lehdestä on poistettu ksi avain. Kuvassa on vain osa B + -puusta. Jokaisen viitteen päässä on joku solmu, jolla voi olla mös lapsia niin, että polku juuresta kaikkiin B + -puun lehtisolmuihin on htä pitkä. T.root 90 T.root 74 99 90 99 67 80 74 80 50 68 69 50 68 69 Jos poiston jälkeen liian vajaaksi jääneessä lehtisolmussa on t 1 avainta ja sen sisaruksessa z vähintään t + 2 avainta, ei solmuja z ja voi hdistää, koska niiden avaimet eivät mahdu samaan solmuun. Tällöin solmujen sisältö jaetaan uudelleen näiden kahden solmun kesken niin, että kumpaankin solmuun tulee lähes htä monta avainta: Poista 53: 47 67 47 67 47 69 50 53 68 69 70 50 68 69 70 50 68 69 70 Koska vanhemman lasten määrä ei muuttunut, tasapainotus on valmis eikä sitä tarvitse enää jatkaa löspäin. Vanhemmassa pitää kuitenkin päivittää solmujen z ja viitteiden välissä olevaa viitta-arvoa.
Mös sisäsolmujen sisältöjä voidaan joutua jakamaan solmujen välillä uudelleen, jos solmujen hdistäminen alempana puussa on saanut aikaan sen, että sisäsolmulla on t 1 lasta ja sen sisaruksella on vähintään t + 2 lasta. Tällöin solmuja erottava viitta-arvo sisarusten vanhemmassa putoaa toiseen käsiteltävistä solmuista ja uudessa jakokohdassa oleva viittaarvo nousee vanhempaan. Seuraavassa esimerkissä vasemmanpuolimmaiselle sisäsolmulle on jäänt vain ksi lapsi alempana tapahtuneen solmujen hdistämisen takia: 13 47 85 13 75 85 60 75 80 47 60 80 Poiston aikavaatimus on sama kuin lisäksellä: Kokonaisaikavaatimus on O(t log t n) Ajantarpeen kätännössä ratkaiseva levhakujen määrä on O(log t n). Mös poisto-operaatioiden htedessä tasapainotus on mahdollista hdistää hakuvaiheeseen: matkalla juuresta lehteen kohdatut puolillaan olevat solmut tasapainotetaan sisaruksensa kanssa.