AND x - Turun yliopiston

Tietorakenteet ja algoritmit II
Turun yliopisto, Informaatioteknologian laitos, periodi 3 / 2012
Lasse Bergroth
Kurssin sisältö
•
Kurssi perustuu oppikirjaan …
Cormen, T. H. – Leiserson, C. E – Rivest, R. L – Stein, C.:
”Introduction to Algorithms”, 3. painos, MIT press (2009)
•
… sekä Jouni Järvisen vuonna 2007 kirjoittamaan luentomonisteeseen.
•
Kyseinen, lähes 1300-sivuinen kirja löytyy myös verkosta brasilialaisen
Recifessä sijaitsevan Pernambucon yliopiston sivuilta osoitteesta
http://www.cin.ufpe.br/~ass4/ALGORITMOS/ALG_3rd.pdf.
Kurssin sisältö (jatkoa)
Sisällysluettelo
•
Luentokalvoissa on mahdollisuuksien mukaan käytetty samaa osa- ja
lukunumerointia kuin oppikirjassa
III Tietorakenteet
12.
13.
Binääriset hakupuut
- toteutus, eri selausjärjestykset
- avaimien lisäys ja poisto
Punamustat puut
- tavoitteena binäärisen hakupuun tasapainottaminen
- toteutus: väriattribuutin lisäys binääriseen hakupuuhun
13U. AVL-puut
- vaihtoehtoinen tapa hakupuun tasapainottamiseksi
- väriattribuutin tilalle lisätty tieto solmun alipuiden välisestä korkeuserosta
- esitellään kirjassa vain lyhyesti
14.
Laajennetut tietorakenteet
- järjestysstatistiikkapuun muodostaminen punamustaan puuhun perustuen
- tavoitteena tehostaa i. pienimmän alkion hakuaikaa luvussa 9 esitetystä
Kurssin sisältö (jatkoa)
V Edistyneitä tietorakenteita
18.
19X.
19.
21.
B-puut
- tietorakenne isojen datamäärien tallentamista varten
- muutos luvussa III esitettyihin tasapainotettuihin puihin: samaan solmuun voidaan
tallentaa useita avaimia
Binomikeot
- keolle vaihtoehtoinen tietorakenne prioriteettijonojen ylläpitoa varten
- lukua ei esiinny kirjan uusimmassa painoksessa
Fibonacci-keot
- ennen luvun käsittelyä tarkastellaan lyhyesti kirjan luvussa 16 esiteltävää
tasoitetun kustannuksen laskentaa
- binomikekoja tehokkaampi tietorakenne prioriteettijonojen operaatioita varten
tasoitetulla kustannuksella mitattuna
Tietorakenteita erillisille joukoille
- toimii johdatuksena graafialgoritmeihin
VI Graafialgoritmeja
22. – 24. Tiivistelmä graafialgoritmeista
- syvyys- ja leveyshaku
- minimaalinen virittävä puu
- lyhimpien polkujen määrääminen graafin yhdestä pisteestä lähtien
12 Binäärinen hakupuu
12.1 Mikä on binäärinen hakupuu?
• Binäärinen hakupuu on tietynlainen binääripuu
sille on määritelty ainakin seuraavat operaatiot:
1) avainarvon haku
2) alkion lisääminen
3) alkion poistaminen
4) minimin etsintä
5) maksimin etsintä
6) alkion edeltäjän määrääminen
7) alkion seuraajan määrääminen
• Binääripuun solmualkiolla x on olemassa seuraavat attribuutit:
avain[x]: esittää solmualkion x avainkentän arvoa
vasen[x]: sisältää osoittimen solmun x vasempaan lapsisolmuun
oikea[x]: sisältää osoittimen solmun x oikeaan lapsisolmuun
vanhempi[x]: sisältää osoittimen solmun x isäsolmuun
jos x on puun juuri, on isäosoitin arvoltaan NIL
• Lisäksi itse binääripuulle P on määritelty attribuutti:
juuri[P]: sisältää osoittimen puun P juuressa sijaitsevaan solmualkioon
jos juuri[P] = NIL, kyseessä on tyhjä puu
12.1 Mikä on binäärinen hakupuu?
• Binäärinen hakupuu -ominaisuus:
Oletetaan, että x on jokin binääriseen hakupuuhun P kuuluva solmu
jos jokin toinen puun P solmu y kuuluu x:n vasempaan alipuuhun, niin tällöin on
voimassa avain[y] ≤ avain[x]
vastaavasti, jos y kuuluu x:n oikeaan alipuuhun, niin avain[y] ≥ avain[x]
Esimerkki binäärisestä hakupuusta:
24
16
7
51
19
29
43
12.1 Mikä on binäärinen hakupuu?
• Tarkastellaan seuraavassa binääripuuta, jonka korkeus on h:
Ensimmäiselle (ylimmälle) tasolle mahtuu 1 = 20 alkiota
Toiselle tasolla mahtuu 2 = 21 alkiota
Kolmannelle tasolle mahtuu 4 = 22 alkiota
…
Alimmalle tasolle (lehtiin) mahtuu 2h alkiota
• Siten täyteen h-korkuiseen puuhun mahtuu alkioita:
n = 20 + 21 + 22 + … + 2h = ∑ 2 = 2h + 1 – 1 kappaletta.
• Tällöin 2h + 1 = n + 1 ja h + 1 = log2(n + 1).
• Siten täyden binäärisen hakupuun korkeus h ≤ log2n, sillä
h = log2(n + 1) – 1
≤ log2(n + n) – 1 /* Silloin, kun n ≥ 1 */
= log2(2n) – 1
= log2n + log22 – 1
= log2n + 1 – 1
= log2n.
12.1 Mikä on binäärinen hakupuu?
• Seuraavassa esitellään tärkeimmät tavat binäärisen hakupuun solmujen läpikäymiseksi.
Oletetaan, että puun solmujen avainarvot halutaan tulostaa.
1) Välijärjestyskulku (solmu käsitellään heti, kun sen koko vasen alipuu on käsitelty, ja
ennen oikeaan alipuuhun siirtymistä)
Kulje vasen alipuu välijärjestyksessä
Vieraile juuressa
Kulje oikea alipuu välijärjestyksessä
VÄLIJÄRJESTYSKULKU(x)
1 IF x ≠ NIL
2 THEN VÄLIJÄRJESTYSKULKU(vasen[x])
3
Tulosta(avain[x]])
4
VÄLIJÄRJESTYSKULKU(oikea[x])
• Välijärjestyksen mukaisesti etenemällä saadaan listattua binäärisen hakupuun solmut
kasvavassa (ei-vähenevässä) järjestyksessä.
12.1 Mikä on binäärinen hakupuu?
2) Esijärjestyskulku (solmu käsitellään heti, kun siihen saavutaan ensimmäistä kertaa)
Vieraile juuressa
Kulje vasen alipuu esijärjestyksessä
Kulje oikea alipuu esijärjestyksessä
3) Loppujärjestyskulku (solmu käsitellään vasta, kun sen molemmat alipuut on jo käsitelty)
Kulje vasen alipuu loppujärjestyksessä
Kulje oikea alipuu loppujärjestyksessä
Vieraile juuressa
Kohtien 2) ja 3) pseudokoodit voidaan muodostaa helposti kohdan 1) perusteella. Kannattaa
huomioida, että triviaalina tapauksena pidetään sitä, kun osoitin x saa arvon NIL.
•
Lause 12.1: Jos x on n-solmuisen binääripuun juuri, niin kutsun VÄLIJÄRJESTYSKULKU(x)
suorittaminen vie ajan Θ(n).
Todistus: Välijärjestyskulun suoritusaikaa kuvaa rekursioyhtälö
T(n) = T(k) + T(n – k – 1) + d,
missä k on vasemman alipuun koko ja d on jokin vakio, joka kuvaa yhden
VÄLIJÄRJESTYSKULKU-algoritmin kutsun suorittamiseen menevää aikaa ilman
rekursiivisia kutsuja (ts. d kuvaa yksittäisen solmun käsittelyyn kuluvaa aikaa).
12.1 Mikä on binäärinen hakupuu?
Induktiolla pystytään helposti osoittamaan, että T(n) = Ο(n):
T(n) = T(k) + T(n – k – 1) + d
≤ c1k + c1(n – k – 1) + d
= c1n – (c1 – d)
≤ c1n /* Silloin, kun c1 ≥ d */
Toisaalta on myös selvää, että T(n) ≥ c2n jollain vakiolla c2, sillä jokaisessa solmussa
joudutaan vierailemaan kertaalleen. Täten T(n) = Θ(n).
12.2 Kyselyt
• Seuraavassa tarkastellaan binäärisiin hakupuihin kohdistuvia kyselyalgoritmeja.
• Rekursiivisessa hakualgoritmissa muuttuja x toimii osoittimena puun juureen, ja k on
etsittävä avain.
HAE_BINÄÄRISESTÄ_HAKUPUUSTA(x, k)
1 IF x = NIL OR k = avain[x]
2 THEN RETURN x
3 IF k < avain[x]
4 THEN RETURN HAE_BINÄÄRISESTÄ_HAKUPUUSTA(vasen[x], k)
5 ELSE RETURN HAE_BINÄÄRISESTÄ_HAKUPUUSTA(oikea[x], k)
12.2 Kyselyt
•
•
•
Hakualgoritmi voidaan helposti muuntaa iteratiiviseksi:
HAE_BINÄÄRISESTÄ_HAKUPUUSTA_ITER(x, k)
1 WHILE x ≠ NIL AND k ≠ avain[x] DO
2
IF k < avain[x]
3
THEN x := vasen[x]
4
ELSE x := oikea[x]
5 RETURN x
Ratkaisutavasta riippumatta haun kustannus on Ο(h), missä h on puun korkeus
Puussa tarkastellaan joka tasolla yhtä alkiota
Parhaassa tapauksessa pelkän juurisolmun tutkiminen riittää (puu tyhjä, tai etsitty alkio
löytyy heti juuresta)
Pahimmassa tapauksessa kuljetaan jokin polku juuresta aina kaukaisimpaan lehteen asti
Minimin etsintä:
Ensimmäisessä kutsussa syöteparametrina annetaan osoitin juuri[P].
BINÄÄRISEN_HAKUPUUN_MINIMI(x)
1 IF x ≠ NIL DO
2 WHILE vasen[x] ≠ NIL DO
3
x := vasen[x]
4 RETURN x
5 ELSE virheilmoitus ”Puu tyhjä: minimiä ei ole määritelty.”
Algoritmi etsii puusta kaikkein vasemmanpuoleisimman alkion (edetään vasemmalle niin kauan
kuin pystytään).
12.2 Kyselyt
• Maksimin etsintä:
BINÄÄRISEN_HAKUPUUN_MAKSIMI(x)
1 IF x ≠ NIL DO
2 WHILE oikea[x] ≠ NIL DO
3
x := oikea[x]
4 RETURN x
5 ELSE virheilmoitus ”Puu tyhjä: maksimia ei ole määritelty.”
Algoritmi etsii puusta kaikkein oikeanpuoleisimman alkion (edetään oikealle niin kauan
kuin pystytään).
• Edellä esitettyjen minimin- ja maksiminhakualgoritmien kompleksisuus on Ο(h), sillä niissä
käydään tarkalleen yksi polku juuresta vasemmalle (tai oikealle) niin pitkälle, kunnes polku
päättyy eli vasenta (oikeaa) lapsisolmua ei enää ole olemassa.
• Pahimmassa tapauksessa joudutaan etenemään juurisolmusta kaukaisimpaan lehteen asti.
• Seuraajan ja edeltäjän etsintä:
Seuraajan määritelmä: Jos puun alkiot lajiteltaisiin avainten mukaan ei-vähenevään
suuruusjärjestykseen, solmun x seuraaja olisi solmu, joka sisältäisi
x:n avainarvoa lähinnä suuremman (tai yhtä suuren) arvon.
12.2 Kyselyt
•
Solmun x seuraajan hakemisen idea:
Jos solmun x oikea alipuu ei ole tyhjä, niin x:n seuraaja on sen oikean alipuun pienin alkio, sillä
kaikki x:ää suuremmat sijaitsevat sen oikeassa alipuussa, ja valitaan niistä se, jonka avainarvo
on pienin. Seuraaja on nyt siis x:n oikean alipuun vasemmanpuoleisin solmu.
Jos x:n oikea alipuu on kuitenkin tyhjä, joudutaan puussa nousemaan taso kerrallaan ylöspäin,
kunnes kohdataan ensimmäinen solmu y, jonka vasempaan alipuuhun x kuuluu. Kyseisessä
alkiossa y on nyt avainarvo, joka on lähinnä avain[x]:ää suurempi, joten y on siten x:n
seuraaja. Ellei tällaista alkiota y ole olemassa, seuraajaa ei ole määritelty, vaan tuolloin
solmussa x on puun arvoltaan suurin avain, jolloin palautetaan tyhjä osoitin NIL.
SEURAAJA_BINÄÄRISESSÄ_HAKUPUUSSA(x)
1 IF oikea[x] ≠ NIL DO
2 THEN RETURN BINÄÄRISEN_HAKUPUUN_MINIMI(oikea[x])
3 y := vanhempi[x]
4 WHILE y ≠ NIL AND x = oikea[y] DO
5
x := y
6
y := vanhempi[y]
7 RETURN x
Algoritmissa edetään solmusta x jotain polkua aina yhteen suuntaan joko alas- tai ylöspäin.
⇒ Aikakompleksisuudeksi saadaan siten Ο(h).
• Solmun x edeltäjä määräytyy puolestaan peilikuvamaisesti edellä esitettyyn nähden seuraavasti:
Jos solmulla x on ei-tyhjä vasen alipuu, x:n edeltäjä on solmu, jossa sijaitsee vasemman
alipuun maksimi. Kyseinen solmu on x:n vasemman alipuun oikeanpuoleisin solmu.
Ellei x:llä ole vasenta lasta, joudutaan puussa nousemaan ylöspäin niin kauan, kunnes
kohdataan ensimmäinen solmu y, jonka oikeaan alipuuhun x kuuluu. Kyseisessä alkiossa on nyt
avainarvo, joka on lähinnä pienempi kuin x:n avainarvo. Ellei tällaista alkiota y ole olemassa,
edeltäjää ei ole määritelty, vaan tuolloin solmussa x sijaitsee arvoltaan puun pienin avain.
Tuolloin palautetaan tyhjä osoitin NIL.
12.3 Lisäys ja poisto
•
•
•
Tarkastellaan ensiksi alkion lisäämistä binääriseen hakupuuhun.
Puuhun lisätään sellainen solmualkio z, jolle on voimassa:
avain[z] = v (jokin avaimen tyypin mukainen arvo)
vasen[z] = NIL
oikea[z] = NIL
Lisäysalgoritmin toiminta-ajatus:
Etsitään sellainen solmu y, jonka lapseksi lisättävä solmu z avainarvonsa puolesta kelpaa ja
lisätään z oikealle paikalleen y:n joko vasemmaksi tai oikeaksi pojaksi.
LISÄÄ_BINÄÄRISEEN_HAKUPUUHUN(P, z)
1 y := NIL
2 x := juuri[P]
3 WHILE x ≠ NIL DO
4
y := x
5
IF avain[z] < avain[x]
6
THEN x := vasen[x]
7
ELSE x := oikea[x]
8 vanhempi[z] := y
9 IF y = NIL
10 THEN juuri[P] = z /* Lisäys tapahtuu tyhjään puuhun. */
11 ELSE IF avain[z] < avain[y]
12
THEN vasen[y] := z
13
ELSE oikea[y] := z
Algoritmissa edetään juuresta jokin polku alaspäin. ⇒ Aikakompleksisuudeksi saadaan siten Ο(h).
12.3 Lisäys ja poisto
• Seuraavaksi esitetään, miten tapahtuu solmualkion z poistaminen binäärisestä hakupuusta.
• Poistossa joudutaan huomioimaan kolme eri tapausta:
1) z on lehtisolmu:
z poistetaan pelkästään isäsolmun viittauksia päivittämällä
2) z:lla on vain yksi lapsi:
z ohitetaan päivittämällä sen ainoan lapsisolmun ja isäsolmun linkkejä
3) z:lla on molemmat lapset:
z:n seuraajalla y ei ole tällöin vasenta lasta (minkä tähden?)
z:n seuraaja y on seuraajan määritelmän perusteella nyt selvästikin z:n oikean alipuun
minimi, koska z:lla on molemmat lapset
talletetaan seuraajan y avainarvo (ja mahdollinen satelliittidata) ja poistetaan seuraajaalkio y
kopioidaan seuraajan tiedot poistettavan alkion z tietojen päälle.
12.3 Lisäys ja poisto
• Solmun poistamisalgoritmi on esitetty seuraavassa:
POISTA_BINÄÄRISESTÄ_HAKUPUUSTA(P, z)
1 IF vasen[z] = NIL OR oikea[z] = NIL
2 THEN y := z
3 ELSE y := SEURAAJA_BINÄÄRISESSÄ_HAKUPUUSSA(z)
4 IF vasen[y] ≠ NIL
5 THEN x := vasen[y]
6 ELSE x := oikea[y]
7 IF x ≠ NIL
8 THEN vanhempi[x] := vanhempi[y]
9 IF vanhempi[y] = NIL
10 THEN juuri[P] = x
11 ELSE IF y = vasen[vanhempi[y]]
12
THEN vasen[vanhempi[y]] := x
13
ELSE oikea[vanhempi[y]] := x
14 IF y ≠ z
15 THEN avain[z] := avain[y]
16
kopioidaan samalla myös y:n mahdollinen satelliittidata solmuun z
17 RETURN y
12.3 Lisäys ja poisto
•
•
•
•
Algoritmin toimintaperiaate on seuraavanlainen:
Riveillä 1 – 3 määräytyy solmu, joka poistetaan puusta fyysisesti
Jos poistettavaksi tarkoitetulta solmulta z puuttuu ainakin toinen lapsista, kopioidaan
osoitin y osoittamaan solmuun z.
Jos z:lla on molemmat lapset olemassa, merkitään y osoittamaan z:n seuraajaa, jolla ei
tässä tilanteessa voi olla vasenta lasta.
Riveillä 4 – 6 asetetaan x osoittamaan siihen y:n lapseen, joka ei ole NIL (nyt jompikumpi
y:n lapsista puuttuu väkisin).
Mikäli tällaista solmua ei ole olemassa, tehdään x:stä solmun y oikea lapsi.
Riveillä 7 – 13 alkio y poistetaan solmujen vanhempi[y] ja x osoittimia päivittämällä
Rivejä 14 – 16 tarvitaan, jos poistettavaksi alkioksi määräytyi z:n seuraaja. Tällöin y:n
tietokenttien sisältö kopioidaan solmuun z.
Rivillä 17 palautetaan vielä osoitin fyysisesti poistettavaan solmuun y, jotta sille
dynaamisesti varattu muistitila voidaan vapauttaa.
Alkion poistamisen kompleksisuus on sama kuin lisäämisen, eli Ο(h).
Lause 12.2: Operaatioiden haku, minimin etsintä, maksimin etsintä, seuraajan hakeminen ja
edeltäjän hakeminen aikakompleksisuus on Ο(h), missä h on binäärisen hakupuun
korkeus.
joudutaan pahimmassa tapauksessa kulkemaan juuresta kaukaisimpaan lehteen tai
päinvastoin.
Lause 12.3: Myös operaatioiden lisäys ja poisto aikakompleksisuus on samoin Ο(h).
haun osuuden kustannus samat kuin edellä, ja linkkien päivitykset ovat vakioaikaisia
12.3 Lisäys ja poisto
• Miten voidaan arvioida kustannustermin Ο(h) suuruutta?
Kuten jo edellä todettiin, täyden binäärisen hakupuun korkeus h ≤ log2n.
Pulmallista on, että usein on mahdotonta aavista etukäteen, millaiseksi puun rakenne
kehittyy.
Varoittava esimerkki: tallennetaan alkiot 11, 15, 24, 29, 39, 71 ja 93 mainitussa
järjestyksessä binääriseen hakupuuhun. Saadaan seuraavanlainen hakupuu (syöttöjärjestys
määrää yksikäsitteisesti sen, miltä puu tulee näyttämään lisäyksen jälkeen):
11
juuri[P]
NIL
15
NIL
24
29
NIL
39
NIL
71
NIL
NIL
93
NIL
NIL
• Hakupuusta muodostuukin juuresta oikealle aukeava lista, jolloin Ο(h) = Ο(n)!
Puu pitäisi pystyä jollain tavoin tasapainottamaan, jotteivät operaatioiden suoritusajat
heikkenisi lineaarisiksi logaritmisista, jollaiset ne olisivat täydelle puulle.
13 Punamustat puut
• Punamusta puu esiteltiin ensimmäistä kertaa vuonna 1972 artikkelissa
Bayer, Rudolf: Symmetric binary B-trees: data structure and maintenance
algorithms, Acta Informatica I (1972), sivut 290 – 306
• Edellisen luvun perusteella muistetaan, että tavallisessa binäärisessä hakupuussa
operaatiot haku, lisäys ja poisto voidaan suorittaa ajassa O(h), missä h on puun korkeus.
• Pulmaksi muodostuu tosiasia, että alkioiden syöttöjärjestys vaikuttaa ratkaisevasti
muodostuvan puun muotoon.
Jos vaikkapa lisätään alun perin tyhjään puuhun järjestyksessä avaimet n, n – 1, …, 1,
kehkeytyy binäärisestä hakupuusta tällöin vasemmalle aukeava lista. Vastaavasti
päinvastainen syöttöjärjestys tuottaisi juuresta oikealle aukeavan listamaisen rakenteen.
Mikäli kaikki puuhun tallennetut avaimet sijaitsevat hakupuussa listamaisesti, tulee puun
korkeudeksi nyt selvästikin n – 1, mikä johtaa pahimmassa tapauksessa Ο(n)-mittaiseen
suoritusaikaan, kun taas täydestä n avainta sisältävästä puusta hakuaika olisi Ο(log2n).
On siten kannattavaa pyrkiä tasapainottamaan puu jollain tavalla!
13.1 Punamustien puiden ominaisuuksia
• Samoin kuin binäärisessä hakupuussa, niin myös punamustassa puussa ovat käytettävissä
seuraavat solmualkion x attribuutit: avain[x], vasen[x], oikea[x] ja vanhempi[x].
• Punamustien puiden solmuilla on näiden lisäksi käytössä attribuutti väri[x].
värin on oltava joko punainen tai musta, ja se voidaan ilmaista yhdellä lisäbitillä.
13.1 Punamustien puiden ominaisuuksia
• Punamustan puun tulee täyttää luvussa 12 esitettyjen binäärisen hakupuun ominaisuuksien
lisäksi seuraavat viisi kriteeriä:
•
•
•
•
•
1) Jokainen solmu on joko punainen tai musta.
2) Puun juuri on musta.
3) Puun jokainen lehtisolmu (NIL-solmu) on musta
4) Puussa ei saa esiintyä kahta punaista solmua peräkkäin
jos solmu on punainen, ovat sekä sen isäsolmu että lapset välttämättä mustia
5) Kuljettaessa mielivaltaisesta punamustapuun solmusta kyseisen alipuun lehtiin
kohdataan matkalla aina sama määrä mustia solmuja riippumatta tehdystä
etenemispolun valinnasta.
Lisäksi koko puulla on käytettävissä attribuutti juuri[P] eli osoitin puun juureen.
Punamustapuussa ainoastaan sisäsolmut ovat sisältönsä kannalta mielenkiintoisia, sillä ne
sisältävät hakuavaimen sekä mahdollista lisä- eli satelliittidataa.
Ulko- eli lehtisolmut toimivat puolestaan yksinomaan pysäytysalkioina (ei dataa säilöttynä).
Koska lehtisolmuilla ei ole mitään muuta hyötykäyttöä kuin polun loppumisen
tunnistaminen, voidaan kaikki lehtisolmut yhdistää käsitteellisti yhdeksi alkioksi.
Seuraavassa esitetään esimerkki punamustasta puusta, johon on tallennettu 20 avainta –
ensiksi kaikkine lehtisolmuineen ja myöhemmin yhdistetyn pysäytysalkion avulla.
jälkimmäiseen kuvaan on lisätty myös tieto solmun ns. mustasta korkeudesta
numeromerkinnällä
13.1 Punamustien puiden ominaisuuksia
26
17
41
14
10
19
16
NIL
7
3
NIL
15
12
NIL
NIL
NIL
NIL
NIL
NIL
28
23
NIL
NIL
NIL
NIL
NIL
39
35
NIL
NIL
NIL
38
20
NIL
47
30
21
NIL
NIL
NIL
NIL
13.1 Punamustien puiden ominaisuuksia
3
26
3
2
17
2
2
14
7
10
16
1
1
15
12
2
47
1
19
23
28
1
38
20
NIL[P]
1
1
1
3
1
1
30
21
1
1
2
1
41
35
1
39
13.1 Punamustien puiden ominaisuuksia
•
Solmun x mustalla korkeudella mk(x) tarkoitetaan matkalla vastaan tulevien mustien solmujen lukumäärää,
kun kuljetaan solmusta x alaspäin mihin tahansa ulkosolmuun (tai edellisen kuvan yhdistettyyn
pysäytyssolmuun NIL[P].
solmua x itseään ei lasketa mukaan mustaan korkeuteen, mutta kylläkin lehtisolmu.
• Mustan korkeuden voidaan sanoa olevan hyvin määritelty, sillä punamustan puun määritelmän kohdan 5
mukaan se on aina sama riippumatta siitä, mitä polkua pitkin lehtitasolle edetään.
• Koko puun P musta korkeus on juuren musta korkeus.
• Lemma 13.1: Punamustapuun korkeus h ≤ 2 log2(n + 1)
Todistus: Määritelmän perusteella vähintään puolet solmuista pitää olla mustia, kun
matkustetaan juuresta mihin tahansa lehteen, sillä
1) Punaista solmua edeltää ja seuraa aina musta solmu
2) Jokaista polulla esiintyvää punaista solmua kohti on olemassa siten
vähintään yksi musta solmu.
Tarkastellaan nyt pisintä polkua juuresta lehteen. Kyseisellä polulla
h = mustien solmujen lukumäärä + suurin esiintyvä punaisten solmujen määrä - 1.
•
•
mustien lukumäärä = mk(P)
punaisten lukumäärä ≤ mk(P)
Kannattaa huomioida, ettei pysäytyssolmuja lasketa mukaan puun normaaliin korkeuteen h.
Siten
h ≤ mk(P) + mk(P) - 1 ≤ 2mk(P), joten mk(P) ≥ h/2.
Jos nyt ajatellaan puuta, jossa on vain mustia solmuja, saadaan:
13.1 Punamustien puiden ominaisuuksia
n ≥ 20 + 21 + 22 + … + 2mk[P] - 1 = 2mk[P] - 1
Tästä seuraa, että n ≥ 2mk[P] - 1 ≥ 2h/2 - 1.
Kun tämä ratkaistaan edelleen h:n suhteen, saadaan:
log2(n + 1) ≥ h/2 ⇔ h ≤ 2log2(n + 1).
• Edellisen lemman perusteella siis h ≤ 2log2(n + 1), josta saadaan edelleen
h ≤ 2log2(n + 1) ≤ 2 log2(3n/2) /* kun n ≥ 2 */
= 2 log2(3/2) + 2log2n
= log2(9/4) + 2log2n
≤ log2n + 2log2n /* kun n ≥ 3 */
= 3 log2n
Siten h = Ο(log2n), ja binäärisen hakupuun operaatiot haku, minimin etsintä, maksimin
etsintä, seuraaja ja edeltäjä voidaan suorittaa nyt ajassa Ο(log2n).
13.1 Punamustien puiden ominaisuuksia
• Kannattaa kuitenkin huomioida, että puun muoto muuttuu sitä mukaa, kun siihen lisätään
uusia solmuja tai kun solmuja poistetaan.
Pulma: Miten voidaan taata, että punamustapuun ominaisuudet säilyvät voimassa myös
alkion lisäys- ja poisto-operaatioiden jälkeen?
• Ratkaisu ongelmaan: kierto-operaatiot eli rotaatiot
• Kierrolla tarkoitetaan paikallista operaatiota, jonka avulla tilapäisesti rikkoutunut
punamustapuu saadaan korjattua takaisin määritelmän vaatimukset täyttäväksi.
• Käytettävissä ovat vasen ja oikea kierto.
• Kiertoja suoritettaessa joudutaan tekemään muutoksia solmujen väriattribuuttien arvoihin.
erilaisia huomioitavia tilanteita on useita
13.2 Kierto-operaatiot
• Paikallisia operaatioita, jotka säilyttävät binäärisen hakupuuominaisuuden.
Hahmotelma:
x
a≤x≤b≤y≤c
vasen kierto kohtaan x
 oikea kierto kohtaan y
y
a
c
x
y
b
c
a
b
13.2 Kierto-operaatiot
• Esitellään seuraavaksi solmulle x vasemman kierron suorittava algoritmi.
VASEN_KIERTO(P, x)
1 y := oikea[x] /* Asetaan solmu y solmun x oikeaksi lapseksi. */
2 oikea[x] := vasen[y] /* Solmun y vasen alipuu siirretään x:n oikeaksi alipuuksi. */
3 IF vasen[y] ≠ NIL[P]
4 THEN vanhempi[vasen[y]] := x
5 vanhempi[y] := vanhempi[x] /* Solmun x isäsolmusta tulee nyt y:n isäsolmu. */
6 IF vanhempi[x] = NIL[P]
7 THEN juuri[P] := y
8 ELSE IF x = vasen[vanhempi[x]]
9
THEN vasen[vanhempi[x]] := y
10
ELSE oikea[vanhempi[x]] := y
11 vasen[y] := x
12 vanhempi[x] := y
• Oikea kierto tapahtuu symmetrisesti (kts. edellinen esimerkkikuva)
• Kumpikin kierto-operaatio saadaan suoritettua vakioajassa Θ(1).
puun koko ei millään tavalla vaikuta algoritmin tekemien operaatioiden määrään.
13.2 Kierto-operaatiot
• Seuraavaksi esiteltävä algoritmi lisää uuden solmun z punamustaan puuhun P.
LISÄÄ_PUNAMUSTAAN_PUUHUN(P, z)
1 y := NIL[P]
2 x := juuri[P]
3 WHILE x ≠ NIL[P] DO
4
y := x
5
IF avain[z] < avain[x]
6
THEN x := vasen[x]
7
ELSE x := oikea[x]
8 vanhempi[z] := y
9 IF y = NIL[P]
10 THEN juuri[P] = z /* Lisäys tapahtuu tyhjään puuhun. */
11 ELSE IF avain[z] < avain[y]
12
THEN vasen[y] := z
13
ELSE oikea[y] := z
14 vasen[z] := NIL[P]
15 oikea[z] := NIL[P]
16 väri[z] := punainen
17 KORJAA_LISÄYS_PUNAMUSTAPUUHUN(P, z) /* Solmun z lisäys saattoi rikkoa
punamustan puun määritelmän mukaisia
ominaisuuksia. */
13.2 Kierto-operaatiot
• Edellä esitetty, solmun z punamustaan puuhun P lisäävä algoritmi toimii täysin samalla
periaatteella kuin tavalliseen binääriseen hakupuuhun solmun lisäävä algoritmi (esiteltiin
luvussa 12).
• Ainoat muutokset tapahtuvat algoritmin neljällä viimeisellä rivillä:
1) lisätyn solmun z lapsilinkit asetetaan osoittamaan pysäytyssolmuun NIL[P]
2) lisättävälle solmulle määrätään väri, ja se on aina punainen
3) lopuksi kutsutaan punamustapuun korjausalgoritmia
• Kannattaa huomioida, että koska uusi solmu värjätään alussa punaiseksi, ei solmun
lisääminen tuo puuhun koskaan uutta mustaa solmua.
Punamustapuun määritelmän ehdot 1, 3, ja 5 pitävät edelleen paikkansa.
• Sen sijaan voi syntyä kaksi pulmatilannetta:
1) kun tyhjään puuhun lisätään ensimmäinen solmu, tulee siitä samalla puun juuri, joka
värjätään nyt punaiseksi vastoin määritelmän sääntöä 2
2) jos puu oli alun perin ei-tyhjä, mutta z:n isäsolmu y on punainen, puuhun tulee nyt
kaksi punaista solmua peräkkäin, mikä rikkoo määritelmän sääntöä 4.
• Pulmatilanteista toipuminen:
Tilanteessa 1 riittää, kunhan juuri jälkikäteen värjätään mustaksi. Juurisolmulla sekä
isä- että kumpikin lapsilinkki osoittavat solmuun NIL[P], joka on musta, eli puu
täyttää jälleen punamustapuun määritelmän kaikki vaatimukset.
13.2 Kierto-operaatiot
• Tilanteessa 2 joudutaan tekemään edellistä enemmän työtä. Tuolloin ollaan tilanteessa,
jossa sekä z että sen isäsolmu ovat kumpikin punaisia, ja z:n molemmat lapsiosoittimet
osoittavat mustaa pysäytyssolmuun NIL[P].
• Korjaaminen käynnistyy nyt tarkastelemalla z:n setäsolmua eli z:n isän velisolmua. Tähän
liittyy kolme erilaista tapausta. Lisäksi oletetaan, että z:n isäsolmu on z:n isoisän vasen
poika (päinvastaisessa tapauksessa tapausta käsitellään tässä esitettävän peilikuvana).
I) z:n setä on punainen
tällöin siis sekä z:n isä että setä ovat punaisia
z:n isoisä välittämättä musta, jotta puu olisi laillinen ennen lisäystä
alustava ratkaisu: värjätään z:n isä ja setä mustiksi sekä isoisä punaiseksi.
Selvästikään musta korkeus ei muutu näiden toimenpiteiden johdosta poluilla, jotka
kulkevat x:n isoisän kautta, sillä niillä tapahtui vain kahden perättäisen kerroksen värien
keskinäinen vaihto.
mahdollinen uusi pulma: entä jos z:n isoisän isä on punainen?
alkuperäinen pulmatilanne toistuu, mutta nyt kahta puun tasoa korkeammalla kuin
viimeksi.
joudutaan jatkamaan korjausalgoritmin suorittamista siirtämällä z alkuperäisestä
puuhun lisätystä solmusta isoisäänsä asettamalla z := vanhempi[vanhempi[z]].
13.2 Kierto-operaatiot
II) z:n setä on musta, ja z on isänsä oikea lapsi
siirretään z osoittamaan punaista isäänsä asettamalla z := vanhempi[z]
suoritetaan vasen kierto solmun z kohdalla
nyt uudesta z:sta tulee isänsä vasen lapsi, mikä johtaa tapaukseen (sekä z että
sen isä ovat edelleen kumpikin punaisia).
III) z:n setä on musta, ja z on isänsä vasen lapsi
värjätään z:n isä mustaksi
värjätään z:n isoisä punaiseksi
suoritetaan z:n isoisän kohdalla oikea kierto
korjausalgoritmin suorittaminen päättyy, sillä sen aloitusehto – z:n isä on
punainen – ei enää toteudu
• Korjausalgoritmin päätteeksi varmistetaan vielä juuren päätyvän mustaksi.
• Tapauksessa II ei tehdä värien vaihtoja, joten minkään alipuun musta korkeus ei muutu siinä
tehtävien toimenpiteiden ansiosta.
• Myöskään tapaus III ei aiheuta muutoksia puun mustan korkeuden tasapainoon, sillä z:n
isän ja isoisän värit vaihdetaan päittäin, ja lopuksi tehtävä oikea kierto z:n isoisän kohdalla
vaihtaa z:n mustaksi värjätyn isän ja punaiseksi värjätyn isoisän keskinäisen järjestyksen.
Siten isoisän kautta kulkevat polut saavat aikaisemmin värien vaihdossa tilapäisesti
menettämänsä yhden mustan takaisin.
esimerkki valaisee asiaa tarkemmin!
13.2 Kierto-operaatiot
• Esimerkki: Lisätään avaimen 4 sisältävä solmu seuraavaan punamustapuuhun (kuvasta on
jätetty pois pysäytyssolmu ja siihen johtavat linkit):
11
2
1
14
19
7
6
10
y
4
z
Kelvoton tilanne: Punaiseksi lisätyn z:n isä on punainen.
z:n isän veli y on punainen Tapaus 1
13.2 Kierto-operaatiot
• Ensimmäinen korjausyritys: värjätään z:n isä ja setä mustiksi ja isoisä punaiseksi
11
2
1
7
6
z
4
14
punaiseksi
10
mustaksi
y
19
13.2 Kierto-operaatiot
• Tilanne 1. korjausyrityksen jälkeen:
11
2
1
19
7
6
z
14
10
y
4
Kelvoton tilanne: Edelleen kaksi punaista peräkkäin, mutta kahta tasoa
ylempänä kuin edellä. Siirretään z osoittamaan isoisäänsä.
uuden z:n isän veli y on musta, ja z on isänsä oikea lapsi
Tapaus 2
13.2 Kierto-operaatiot
• Toinen korjausyritys: siirretään z osoittamaan isäänsä, ja tehdään sen kohdalla vasen
kierto-operaatio (värit eivät muutu)
11
2
14
uusi y
1
7
6
19
uusi z
10
y
4
z
Kelvoton tilanne: Edelleen kaksi punaista peräkkäin, mutta kahta tasoa
ylempänä kuin edellä. Siirretään z osoittamaan isoisäänsä.
uuden z:n isän veli y on musta, ja z on isänsä oikea lapsi
Tapaus 2
13.2 Kierto-operaatiot
• Toinen korjausyritys: siirretään z osoittamaan isäänsä, ja tehdään sen kohdalla vasen
kierto-operaatio (värit eivät muutu)
11
vasen kierto
uusi z
2
1
14
19
7
z
6
4
y
10
13.2 Kierto-operaatiot
11
y
14
7
z
10
2
19
6
1
4
Kelvoton tilanne: Edelleen kaksi punaista peräkkäin (z ja isänsä)
uuden z:n setä eli isän veli y pysyy ennallaan (edelleen musta),
mutta nyt z muuttui isänsä vasemmaksi lapseksi
Tapaus 3
13.2 Kierto-operaatiot
• Kolmas korjausyritys: värjätään z:n isä mustaksi, isoisä punaiseksi, ja tehdään tämän
kohdalla oikea kierto-operaatio
oikea kierto z:n isoisän kohdalla
11 z:n isoisä punaiseksi
7
z
10
2
6
1
4
z:n isä
mustaksi
14
y
19
13.2 Kierto-operaatiot
7
z
11
2
6
1
10
y
14
19
4
Nyt saatiin lopputulokseksi jälleen kaikki viisi kriteeriä täyttävä punamustapuu!
• Kannattaa erityisesti huomioida, että viimeksi suoritettu oikea kierto takaa sen, että z:n
aikaisemman isäsolmun (arvo 11) kautta kulkevien polkujen musta korkeus ei pienene värin
vaihdon takia.
13.2 Kierto-operaatiot
• Seuraavassa on esitelty punamustan puun lailliseksi korjaava algoritmi
KORJAA_LISÄYS_PUNAMUSTAPUUHUN(P, z)
1 WHILE väri[vanhempi[z]] = punainen DO
2
IF vanhempi[z] = vasen[vanhempi[vanhempi[z]]]
3
THEN y = oikea[vanhempi[vanhempi[z]]] /* z:n setäsolmun määrääminen */
4
IF väri[y] = punainen /* Tapaus 1 */
5
THEN väri[vanhempi[z]] := musta
6
väri[y] := musta
7
väri[vanhempi[vanhempi[z]]] := punainen
8
z := vanhempi[vanhempi[z]]
9
ELSE IF z = oikea[vanhempi[z]] /* Tapaus 2 */
10
THEN z := vanhempi[z]
11
VASEN_KIERTO(P, z)
12
väri[vanhempi[z]] := musta
13
väri[vanhempi[vanhempi[z]]] := punainen
14
OIKEA_KIERTO(P, vanhempi[vanhempi[z]])
15
ELSE /* kuten rivien 3 – 14 lauseet, mutta oikea  vasen
16 väri[juuri[P]] := musta
13.2 Kierto-operaatiot
• Lisäyksen kompleksisuuden analyysi:
Alkuosa algoritmista (rivit 1 – 13) on lähes identtinen binääriseen hakupuuhun
tehtävän lisäyksen kanssa, joten sen kompleksisuus on Ο(h).
Rivit 14 – 16 ovat vakioaikaisia sijoituksia (lapsilinkit NIL[P]:hen + väriattribuutin
asettaminen uudelle solmulle)
Myös riviltä 17 kutsuttavan korjausalgoritmin suoritusaika on Ο(h), sillä riviltä 1
käynnistyvää WHILE-silmukkaa joudutaan toistamaan vain tapauksessa 1, jossa
osoitinta z nostetaan joka kierroksella 2 tasoa ylöspäin. Kaikki muut operaatiot
korjausalgoritmissa ovat vakioaikaisia.
Koko lisäysalgoritmin suoritusaika on siten
Ο(h) + Ο(h) = Ο(h)
Koska puun korkeus on h = Ο(log2n), on algoritmin kompleksisuus Ο(log2n).
• Lisäksi kannattaa huomioida, että kierto-operaatioita joudutaan suorittamaan korkeintaan
kahdesti (tapauksen 2 esiintyessä).
13.3 Solmun poistaminen
• Punamustasta puusta solmun poistamisen perusajatus on sama kuin tavallisessa
binäärisessä hakupuussakin.
• Poistomenettely perustuu poistettavan solmun z lapsien määrään.
Jos solmulla z on 0 – 1 lasta, kyseinen solmu poistetaan fyysisesti, ja tehdään lisäksi
solmun ohitus linkkejä päivittämällä, jos z:lla on 1 lapsi.
Jos z:lla on 2 lasta, poistetaankin fyysisesti z:n seuraaja y, jolla on korkeintaan 1 lapsi
(vasen lapsi puuttuu väistämättä), ja seuraajan arvot kopioidaan solmun z vastaaviin
datakenttiin.
• Jos fyysisesti poistettava solmu on punainen, ei seuraa mitään ongelmia.
• Sen sijaan mustan solmun poistaminen aiheuttaa väkisin jonkin tyyppisiä ongelmia:
1) Puun juurisolmu y poistetaan, ja uudeksi juureksi päätyy tämän punainen lapsi x.
rikotaan määritelmän vaatimusta 2, että puun juuri on musta
2) Jos sekä x että vanhempi[y] (josta tulee nyt vanhempi[x]) ovat punaisia, tulee puuhun
kaksi punaista solmua peräkkäin
3) Niiltä poluilta, jotka kulkivat poistetun solmun y kautta, häviää yksi musta, joten
musta korkeus näillä poluilla pienenee
• Ratkaisuyritys: pyritään siirtämään poistetun solmun musta väri alaspäin sen lapseen x
jos lapsi x on jo ennestään musta, siitä tulee nyt ”tuplamusta”
uusi ratkaisu: esitellään korjausalgoritmi
KORJAA_POISTO_PUNAMUSTAPUUSTA(P, x)
13.3 Solmun poistaminen
• Seuraavassa on esitelty punamustasta puusta poiston perusalgoritmi:
POISTA_PUNAMUSTAPUUSTA(P, z)
1 IF vasen[z] = NIL[P] OR oikea[z] = NIL[P]
2 THEN y := z
3 ELSE y := SEURAAJA_BINÄÄRISESSÄ_HAKUPUUSSA(z)
4 IF vasen[y] ≠ NIL[P]
5 THEN x := vasen[y]
6 ELSE x := oikea[y]
7 vanhempi[x] := vanhempi[y]
8 IF vanhempi[y] = NIL[P]
10 THEN juuri[P] = x
11 ELSE IF y = vasen[vanhempi[y]]
12
THEN vasen[vanhempi[y]] := x
13
ELSE oikea[vanhempi[y]] := x
14 IF y ≠ z
15 THEN avain[z] := avain[y]
16
kopioidaan samalla myös y:n mahdollinen satelliittidata solmuun z
17 IF väri[y] = musta
18 THEN KORJAA_POISTO_PUNAMUSTAPUUSTA(P, x)
19 RETURN y
13.3 Solmun poistaminen
•
•
•
•
•
•
Lähdetään seuraavaksi tarkastelemaan punamustapuusta poistoon liittyvää korjausalgoritmia.
Jos väri[x] = musta, tulee x:stä tilapäisesti tuplamusta.
Tarkastellaan solmun x veljeä w, joka ei voi olla NIL[P], koska x on tuplamusta
muussa tapauksessa puun musta korkeus ei olisi ollut tasapainossa joko x:n tai sen veljen
w kohdalla ennen poistoa.
Punamustapuusta tapahtuvan mustan solmun poistoon liittyy neljä eri tapausta peilikuvineen
(riippuen siitä, miltä puolelta solmun x veli löytyy).
Tapaus 1: Poistetun solmun lapsisolmun x veli w on punainen, jolloin w:n lapset ovat
välttämättä mustia.
Vaihdetaan w:n ja vanhempi[x]:n värit keskenään
Tätä seuraa vasen kierto x:n isäsolmun eli vanhempi[x]:n kohdalla
Tapaus muuttuu joksikin tapauksista 2, 3 tai 4, joissa kaikissa x:n velisolmu w
on musta.
Tapaus 2: Poistetun solmun lapsisolmun x veli w on musta, ja myös veljen lapset ovat
kumpikin mustia.
Koska velisolmu w on nyt musta, ja x on tuplamusta, poistetaan näistä molemmista
yksi musta. Tämä tapahtuu
poistamalla tuplamustasta x toinen musta
värjäämällä w punaiseksi
Poluilta, jotka kulkevat x:n ja w:n isäsolmun kautta, hävisi täten yksi musta. Tämä
palautetaan polulle takaisin värjäämällä kyseinen isäsolmu mustaksi.
kaikki sujuu hyvin, jos mainittu isäsolmu on punainen
muussa tapauksessa isäsolmusta tulee nyt kaksinkertaisesti musta, eli
alkuperäinen ongelma uusiutuu yhtä tasoa ylempänä.
13.3 Solmun poistaminen
•
Kannattaa huomioida, että jos tapaukseen 2 tultiin tapauksen 1 kautta, on
x:n isäsolmu punainen (entinen velisolmun w väri)
Lisäksi kannattaa huomioida, että jos x on puun juuri ja samalla tuplamusta,
ei tarvitse tehdä enää mitään (musta korkeus jo korjautunut, sillä juuren
musta väri vaikuttaa kaikkiin polkuihin).
Tapaus 3: Poistetun solmun lapsisolmun x veli w on musta, ja sillä on punainen vasen ja
musta oikea lapsi
Nyt veljen w vasemman lapsen lasten on oltava mustia.
Vaihdetaan päittäin w:n ja sen vasemman lapsen väri.
Lisäksi tehdään vielä oikea kierto velisolmun kohdalla.
Nyt x:n uusi veli on musta (se on nyt veljen aikaisempi vasen lapsi, joka värjättiin
edellä mustaksi), ja sillä on punainen oikea lapsi (entinen x:n veli, joka värjättiin
punaiseksi) ja musta vasen (alkuperäinen) lapsi. Tilanne johtaa tapaukseen 4.
•
•
Tapaus 4: Poistetun solmun lapsisolmun x veli w on musta, ja sillä on punainen oikea lapsi
(paikka ylimääräisen mustan sijoittamista varten)
Asetetaan w:n väriksi x:n (ja samalla w:n) isäsolmun väri (ei tiedossa)
Asetetaan x:n isäsolmun väriksi musta (x:n sisältämä ylimääräinen musta)
Veljen w oikean lapsen väriksi asetetaan musta (w:ssä sijainnut musta)
Tehdään vasen kierto x:n isäsolmun kohdalla, jolloin isäsolmu siirtyy
vasempaan haaraan.
Lopuksi siirretään osoitin x osoittamaan puun juureen, mihin poiston
korjausalgoritmin suoritus päättyy.
Esitetään seuraavaksi esimerkkejä kaikista neljästä tapauksesta!
13.3 Solmun poistaminen
• Lähtötilanne: On poistettu musta solmu y avainarvot B ja A sisältävien solmujen välistä,
jolloin solmun A kohdalta alkava alipuu on noussut tasoa ylöspäin.
B
x
(y)
w
D
A
a
b
E
C
c
d e
f
Tapaus 1: Poistetun mustan solmun y lapsisolmusta x tulee tuplamusta, kun y:n musta väri
pakotetaan tämän ainoaan lapsisolmuun (avainarvo A), joka sattuu olemaan
väriltään musta. Tuplamustasta väristä solmussa x pitää päästä eroon.
Solmun x veli w on punainen.
13.3 Solmun poistaminen
• 1. korjausvaihe: i) Vaihdetaan x:n isä- ja velisolmujen värit keskenään
ii) Suoritetaan vasen kierto x:n isäsolmun kohdalla.
B
x
(y)
w
D
A
a
b
E
C
c
d e
f
13.3 Solmun poistaminen
• Muodostuu jokin tapauksista 2, 3 tai 4, joissa kussakin x:n velisolmu on musta.
D
E
B
x
e
C
A
a
f
b
c
d
Tapaus 2: Oletetaan seuraavaksi, että x:n veljen molemmat lapset ovat mustia.
13.3 Solmun poistaminen
• Tapaus 2: Solmun x veli on musta, ja sen kumpikin lapsi on musta. Sen sijaan solmun x isän
väri voi olla kumpi tahansa (merkitty vihreällä).
B
x
D
A
a
b
c
Toimenpiteet:
w
E
C
d
e
f
i) Solmusta x poistetaan toinen musta
ii) Solmu w värjätään punaiseksi (sieltäkin poistuu yksi musta)
iii) Värjätään näiden isäsolmu B mustaksi
Jos solmu B on alun perin punainen, tilanne tulee kuntoon
Muussa tapauksessa B:stä tulee nyt tuplamusta, jolloin osoitin
x siirretään isäänsä eli tasoa ylemmäs.
13.3 Solmun poistaminen
• Tilanne edellisten toimenpiteiden jälkeen:
x
Mustien lukumäärä 1 vai 2?
B
D
A
a
b
E
C
c
Toimenpiteet:
d
e
f
i) Solmusta x poistetaan toinen musta
ii) Solmu w värjätään punaiseksi (sieltäkin poistuu yksi musta)
iii) Värjätään näiden isäsolmu B mustaksi
Jos solmu B on alun perin punainen, tilanne tulee kuntoon
Muussa tapauksessa B:stä tulee nyt tuplamusta, jolloin osoitin
x siirretään isäänsä eli tasoa ylemmäs.
13.3 Solmun poistaminen
• Tapaus 3: Solmun x velisolmu w on musta, veljen vasen lapsi on punainen ja oikea musta
B
x
D
A
a
w
b
E
C
c
Toimenpiteet:
d
e
f
i) Vaihdetaan x:n veljen w ja sen vasemman lapsen värit keskenään
veljestä tulee punainen ja vasemmasta lapsesta musta
ii) Suoritetaan oikea kierto w:n kohdalla
tulokseksi saadaan tapaus 4, joka on nähtävissä seuraavalla sivulla
13.3 Solmun poistaminen
• Tapaus 4: Solmun x velisolmu w on musta, veljen vasen lapsi on musta ja oikea punainen
B
x
a
w
C
A
b
c
D
d
E
e
f
13.3 Solmun poistaminen
• Tapaus 4: Solmun x velisolmu w on musta, ja veljen oikea lapsi on punainen
B
x
a
D
A
w
b
E
C
c
Toimenpiteet:
d e
f
i) Vaihdetaan veljen w väriksi x:n isän väri
ii) Siirretään x:n ylimääräinen musta sen isäsolmuun
iii) Asetetaan w:n oikean lapsen väriksi musta (velisolmun musta)
iv) Tehdään vasen kierto x:n isäsolmulle
v) Siirretään osoitin x koko puun juureen.
13.3 Solmun poistaminen
• Lopputilanne: Puu täyttää jälleen punamustapuulle asetettavat kriteerit
D
E
B
e
a
f
C
A
b
c
w
d
13.3 Solmun poistaminen
•
Seuraavassa on esitelty punamustasta puusta poiston korjausalgoritmi:
KORJAA_POISTO_PUNAMUSTAPUUSTA(P, x)
1 WHILE x ≠ juuri[P] AND väri[x] = musta DO
2 IF x = vasen[vanhempi[x]]
3 THEN w := oikea[vanhempi[x]] /* Määrätään solmun x velisolmun sijainti. */
4
IF väri[w] = punainen
5
THEN väri[w] := musta /* Tapaus 1 */
6
väri[vanhempi[x]] := punainen
7
VASEN_KIERTO(P, vanhempi[x]]
8
w := oikea[vanhempi[x]]
9
IF väri[vasen[w]] = musta AND väri[oikea[w]] = musta
10
THEN väri[w] = punainen /* Tapaus 2 */
11
x := vanhempi[x]]
12
ELSE IF väri[oikea[w]] = musta
13
THEN väri[vasen[w]] := musta /* Tapaus 3 */
14
väri[w] = punainen
15
OIKEA_KIERTO(P, w)
16
w := oikea[vanhempi[x]]
17
väri[w] := väri[vanhempi[x]] /* Tapaus 4 */
18
väri[vanhempi[x]] := musta
19
väri[oikea[w]] := musta
20
VASEN_KIERTO(P, vanhempi[x])
21
x := juuri[P]
22 ELSE samoin kuin rivit 3 – 21, mutta vasen  oikea
23 väri[x] := musta
13.3 Solmun poistaminen
• Analysoidaan seuraavaksi vielä poiston kompleksisuus
Poiston alkuosan (eli rivien 1 – 15) kompleksisuus on sama kuin poistettaessa solmua
tavallisesta binäärisestä hakupuusta siis O(h).
Korjausalgoritmin kompleksisuus on samoin O(h), sillä tapauksissa 1, 3 ja 4 suoritus
loppuu heti, kun on tehty vakiomäärä värien muutoksia ja enintään kolme kiertoa
WHILE-silmukkaa joudutaan (mahdollisesti) toistamaan ainoastaan tapauksessa 2.
Tällöin osoitinta x siirretään joka kierroksella yksi askel ylöspäin puussa.
• Siten koko poisto-operaation kompleksisuus on:
O(h) + O(h) = O(h) = O(log2n)
14 Laajennetut tietorakenteet
14.1 Dynaaminen järjestysstatistiikka
• Syksyllä pidetyllä kurssilla Tietorakenteet ja algoritmit I tarkasteltiin luvussa 9 seuraavaa
ongelmaa:
Mikä on annetun lukujoukon i. pienin alkio?
• Tuolloin osoitettiin, että ongelma voidaan ratkaista ajassa Ο(n), jos luvut on tallennettu
taulukkoon.
• Tässä luvussa osoitetaan, että ongelma ratkeaa kuitenkin ajassa Ο(log2n), mikäli sen
ratkaisemisessa käytetään hyväksi punamustia puita.
• Lisäksi esitellään menetelmä, joka selvittää mielivaltaisen alkion arvoasteen ajassa Ο(log2n).
• Termillä arvoaste tarkoitetaan, monentenako kysytty alkio esiintyisi järjestetyssä lukujoukossa.
• Järjestysstatistiikkapuu:
Sisältää kaikki punamustan puun ominaisuudet
Solmualkioilla on lisäksi yksi uusi attribuutti
• Solmualkion attribuutit:
vanhempi, avain, vasen, oikea, väri, …
… ja näiden lisäksi vielä koko
14.1 Dynaaminen järjestysstatistiikka
• Attribuutti koko[x] osoittaa solmun x kohdalta alkavan alipuun koon eli solmujen lukumäärän
(pysäytyssolmuja ei lasketa tähän mukaan)
Ominaisuudet:
koko[NIL[P]] = 0
koko[x] := koko[vasen[x]] + koko[oikea[x]] + 1
Esimerkki järjestysstatistiikkapuusta:
13
15
16
5
8
9
11
3
5
5
3
3
1
1
6
1
4
1
9
1
18
3
14
1
12
1
17
1
19
1
14.1 Dynaaminen järjestysstatistiikka
•
•
•
•
•
Tarkastellaan, miten tiettyä arvoastetta i oleva luku löydetään järjestysstatistiikkapuusta.
Seuraava algoritmi VALITSE_I._ALKIO(x, i) palauttaa osoittimen sellaiseen solmualkioon y, jossa
avain[y] on x-juurisen alipuun i. pienin alkio.
VALITSE_I._ALKIO(x, i)
1 r := koko[vasen[x]] + 1
2 IF i = r
3 THEN RETURN x
4 ELSE IF i < r
5 THEN RETURN VALITSE_I._ALKIO(vasen[x], i)
6 ELSE RETURN VALITSE_I._ALKIO(oikea[x], i – r).
Jos etsitään koko puun P i. alkiota, kutsu on muotoa VALITSE_I._ALKIO(juuri[P], i)
Algoritmin toiminta-ajatus:
muistuttaa pitkälti luvussa 9 esitetyn algoritmin ideaa
arvo koko[vasen[x]] kertoo, kuinka monta alkiota on järjestyksessä ennen x:ää
siten r = koko[vasen[x]] + 1 on alkion x arvoaste sellaisessa puussa, jonka juuri on solmu x.
jos i = r, on x samalla etsitty solmu ja voidaan lopettaa
jos i < r, löytyy i. alkio rekursiivisesti vasemmasta alipuusta
jos i > r, niin i. alkio löytyy oikeasta alipuusta. Koska ennen x:n oikean alipuun alkioita on
puussa r kappaletta tätä pienempiä alkioita, on puun i. alkio nyt oikean alipuun i – r. alkio.
Algoritmin kompleksisuus on Ο(log2n), sillä jokainen rekursiivinen kutsu johtaa puussa aina tasoa
alemmas, kullakin tasolla tehdään vakiomäärä työtä, ja kutsuja muodostuu korkeintaan Ο(log2n).
14.1 Dynaaminen järjestysstatistiikka
•
•
•
Seuraavaksi tutkitaan, miten pystytään selvittämään tietyn yksittäisen järjestysstatistiikkapuun alkion
x arvoaste .
Käytettävissä on osoitin puun P johonkin solmuun x.
Seuraavassa esitetty algoritmi selvittää, monesko solmuun x tallennettu avain on arvoasteen
mukaisessa järjestyksessä puussa P.
ARVOASTE(P, x)
1 r := koko[vasen[x]] + 1
2 y := x
3 WHILE y ≠ juuri[P] DO
4
IF y = oikea[vanhempi[y]]
5
THEN r := r + koko[vasen[vanhempi[y]]] + 1
6
y := vanhempi[y]
7 RETURN r
•
Algoritmin toiminta-ajatus:
1) jos solmu x on puun P juuri, saadaan sen arvoaste suoraan selville laskemalla sen
vasemman alipuun koko ja lisäämällä siihen ykkönen (juuri itse), ja lopetetaan
2) muuten, jos solmu x kuuluu isäsolmunsa oikeaan alipuuhun, on arvoasteeseen lisättävä
myös isäsolmu sekä tämän vasempaan alipuuhun kuuluvat solmut
3) jos taas x kuuluu isänsä vasempaan alipuuhun, ei tehdä kyseisellä silmukan kierroksella mitään
tapausten 2 ja 3 jälkeen siirrytään lopuksi puussa tasoa ylöspäin nostamalla osoitin y osoittamaan
nykyiseen isäsolmuunsa; tehtävä on valmis, kun y osoittaa lopulta puun juureen
14.1 Dynaaminen järjestysstatistiikka
• Todetaan seuraavassa vielä algoritmin oikeellisuus:
1) Kunkin silmukassa tehtävän kierroksen lopussa siis nostetaan osoitinta y tason verran
ylöspäin solmuun vanhempi[y]. Mikäli silmukan alkaessa r edustaa avain[x]:n arvoastetta
puussa, jonka juurena esiintyy y, niin silmukan lopussa r osoittaa arvoastetta puussa,
jonka juurena on vanhempi[y].
2) Suoritettaessa WHILE-silmukkaa tarkastellaan aina alipuuta, jonka juuri on vanhempi[y].
Tässä vaiheessa on jo ehditty summaamaan x:n arvoasteeseen r ne y-juurisen puun
solmut, jotka edeltävät x:ää. Silmukan kierroksen aikana kasvatetaan arvoa r y:n isän
vasemman alipuun koolla + 1:llä, sillä nämä edeltävät puussa x:ää, kunhan y esiintyy
isänsä oikeassa alipuussa.
3) Jos puolestaan y esiintyy isänsä vasemmassa alipuussa, eivät sen kummemmin
vanhempi[y] kuin tämän oikeassa alipuussakaan olevat solmut edellä x:ää. Tällöin ei ole
tarvetta päivittää x:n arvoasteen r arvoa silmukassa kyseisellä kierroksella.
• Esitellään luennolla esimerkki algoritmin toiminnasta.
• Algoritmin ARVOASTE(P, x) kompleksisuus on Ο(log2n), sillä pahimmassa tapauksessa x
osoittaa juuresta katsottuna kaukaisimpaan datasolmuun (ei NIL-arvon sisältävään solmuun).
Koska puun korkeus on logaritminen ja silmukassa toistettavat lauseet ovat vakioaikaisia, kuten
myös rivien 1, 2 ja 7 operaatiot, on kokonaissuoritusaika pahimmassa tapauksessa
logaritminen.
14.1 Dynaaminen järjestysstatistiikka
• Siirrytään seuraavaksi tarkastelemaan alipuiden kokojen ylläpitoa.
Pulma: sekä solmun lisäys- että poisto-operaatiot muuttavat puuta.
on osattava päivittää attribuuttia koko
• Tarkastellaan ensiksi lisäystä:
Lisäysalgoritmi LISÄÄ_PUNAMUSTAAN_PUUHUN(P, z) on kaksivaiheinen:
1) Ensiksi uusi solmu viedään oikealle paikalleen kuten tavalliseen binääriseen
hakupuuhun lisättäessä.
2) Algoritmilla KORJAA_LISÄYS_PUNAMUSTAPUUHUN(P, z) korjataan värit, jotta puu
täyttää lisäyksen jälkeenkin kaikki punamustapuun kriteerit.
• Muutokset järjestysstatistiikkapuussa:
Vaihe 1: Solmun paikkaa etsittäessä lisätään jokaisen vastaantulevan solmun x attribuutin
koko arvoa yhdellä.
Vaihe 2: Ainoastaan kierto-operaatiot eli rotaatiot muuttavat puun rakennetta. Kierto on
paikallinen operaatio: ainoastaan kahden solmun koko-attribuutin arvoa
joudutaan päivittämään (solmujen x ja y).
vasen kierto kohtaan x 51
26
x
 oikea kierto kohtaan y y 19
19
y
6
4
51
12
x
7
6
26
11
7
4
14.1 Dynaaminen järjestysstatistiikka
• Edellisestä – kiertoja yleisesti esittävästä – kuvasta voidaan päätellä, että kierrossa keskenään
paikkoja vaihtavien solmujen x ja y alipuiden koot pysyvät ennallaan.
• Myöskään kiertokohdan yläpuolella puussa ei selvästikään tapahdu mitään muutoksia.
• Sen sijaan solmujen x ja y koko-attribuuttien arvot määräytyvät seuraavasti:
vasemmassa kierrossa y:n attribuutin koko arvoksi tulee x:n koko ennen kierron aloitusta
attribuutin koko[x] arvoksi saadaan puolestaan laskemalla x:n vasemman alipuun (sama
kuin ennenkin) ja uuden oikean alipuun (entinen y:n vasen alipuu) koot yhteen ja lisäämällä
summaan ykkönen (solmu x itse).
• Jos suoritetaan puolestaan oikea kierto, ovat tehtävät päivitykset edellisen peilikuvia:
x:n uudeksi kokoattribuutin arvoksi tulee y:n koko ennen kierron käynnistymistä
y:n uusi koko on vastaavasti sen alipuiden kokojen summa + 1 (y:n oikea alipuu on sama
kuin ennenkin, ja vasemman alipuun kooksi tulee x:n entisen oikean alipuun koko).
• Algoritmiin VASEN_KIERTO(P, x) joudutaan siten lisäämään seuraavat rivit:
13 koko[y] := koko[x]
14 koko[x] := koko[vasen[x]] + koko[oikea[x]] + 1
• Algoritmiin OIKEA_KIERTO(P, y) (algoritmia ei ole esiteltynä monisteessa eksplisiittisesti)
tehdään vastaavasti lisäykset:
13 koko[x] := koko[y]
14 koko[y] := koko[vasen[y]] + koko[oikea[y]] + 1
14.1 Dynaaminen järjestysstatistiikka
•
•
•
Järjestysstatistiikkapuuhun lisäämisen kompleksisuus:
Vaihe 1: Koska puun jokaisella tasolla joudutaan vaihtamaan korkeintaan yhden solmun
koko-attribuutin arvoa, on tarvittavan lisätyön kustannus Ο(log2n).
Vaihe 2: Korjausalgoritmissa suoritetaan korkeintaan 2 rotaatiota, joiden yhteydessä
joudutaan suorittamaan edellisellä sivulla esiintyvät ylimääräiset kaksi komentoa.
Näistä aiheutuvan lisätyön kustannus on siten Ο(1).
Siten alkion järjestysstatistiikkapuuhun lisäämisen kokonaiskustannus on Ο(log2n).
Tarkastellaan seuraavaksi poiston yhteydessä tarvittavia muutoksia.
1) Aluksi poistetaan haluttu solmu (tai sen seuraaja) aivan kuten tavallisesta binäärisestä
hakupuusta.
2) Algoritmilla KORJAA_POISTO_PUNAMUSTAPUUSTA(P, x) saadaan puu palautettua
lailliseksi tekemällä tarpeelliset kierrot ja värien korjaukset. Korkeintaan kolme kiertoa
joudutaan suorittamaan (tapausjono 1 3 4).
Tarpeelliset muutokset järjestysstatistiikkapuussa:
Vaihe 1: Kun fyysisesti poistettava solmu y on paikallistettu, palataan sieltä kohti juurta ja
pienennetään jokaisen vastaan tulevan solmun koko-attribuutin arvoa yhdellä.
(KYSYMYS: Miksi ei voida koko-attribuutin päivityksiä tehdä vielä ’menomatkalla’?)
Vaihe 2: Korjausalgoritmia suoritettaessa joudutaan koko-attribuutteja päivittämään
ainoastaan kiertoja tehtäessä. Tämä tapahtuu täysin samaan tapaan kuin solmua
lisättäessä (kts. edellä). Rotaatioita tapahtuu korkeintaan kolme.
Koska vaiheessa 1 joudutaan pahimmassa tapauksessa kulkemaan pisin polku alimmalta tasolta
juureen ja tekemään joka tasolla yhden koko-attribuutin päivitys, ja vaiheessa 2 tehdään
vakiomäärä lisätyötä, on alipuiden kokotiedon ylläpidosta koituvan lisätyön kustannus
logaritminen, pysyy poiston kokonaiskustannus suuruusluokassa Ο(log2n).
järjestysstatistiikkapuun käsittelyn asymptoottinen kustannus on siis sama kuin tavallisen
punamustan puun.
14.2 Kuinka tietorakennetta laajennetaan?
•
•
•
Edellä tarkasteltiin, miten punamustapuun ominaisuuksia laajentamalla saatiin aikaan tietorakenne, joka soveltuu
järjestysstatistiikkatiedon ylläpitoon.
Yleisesti tietorakenteen laajentamiselle on olemassa neljä perusperiaatetta:
Vaihe 1: Valitaan lähtökohdaksi sopiva perustietorakenne, jonka ominaisuudet peritään ja
säilytetään.
Vaihe 2: Määritellään tarvittava lisäinformaatio.
Vaihe 3: Varmistetaan, että lisäinformaatiota voidaan ylläpitää (tarpeeksi helposti!)
modifioimalla perustietorakenteen operaatioita.
Vaihe 4: Toteutetaan uudet operaatiot.
Palataan esimerkin vuoksi takaisin järjestysstatistiikkapuihin:
Vaihe 1: Valitaan punamustat puut lähtökohtaiseksi tietorakenteeksi.
kaikki niiden ominaisuudet ovat käytettävissä
Vaihe 2: Määritellään punamustalle puulle uusi attribuutti koko, joka sisältää
tarvitsemamme lisäinformaation.
Vaihe 3: Selvästikään uuden attribuutin lisäämisestä ei ole kiusaa kohdistettaessa puuhun
kyselyoperaatioita. Sen sijaan pitää varmistaa, etteivät lisäyksen ja poiston
teoreettiset kustannukset kasva uuden attribuutin käyttöönoton takia. Edellä
analysoitiin, että näiden operaatioiden kustannus pysyy yhä edelleen suuruusluokan
Ο(log2n) mukaisina.
HUOM! Kannattaa huomioida, että järjestyksessä i. alkion palauttamiseen tai alkion x arvoasteen
määräämiseen tarkoitetut algoritmit nopeutuisivat jopa vakioaikaisiksi (!), jos alipuun
kokotiedon sijaan solmuun tallennettaisiinkin suoraan sen arvoaste … . Mutta hyvällä
ajatuksella on tällä kertaa kuitenkin hintansa: solmun lisäämisen tai poistamisen vaikutukset
eivät enää rajoittuisikaan paikallisiksi vaan heijastuisivat koko puuhun. Siten nopeiden,
ajassa Ο(1) tapahtuvien kyselyjen vastapainoksi tulisivat selvästi hitaammat, Ο(n)-aikaiset
päivitykset!
Vaihe 4: Toteutetaan tietorakenteen uudet operaatiot VALITSE_I:_ALKIO(x, i) ja ARVOASTE(P, x).
13U AVL-puut
• AVL-puun nimitys tulee kehittäjiensä sukunimistä G. M. Adelson-Velskij ja E. M. Landis.
Tietorakenne on esitelty jo vuonna 1962 Neuvostoliitossa artikkelissa An algorithm for the
organisation of information, Доклады Академии Наук СССР [Soviet Mathematics Doklady]
3 (1962), sivut 1259 – 1263.
• Edellä luvussa 13 esiteltiin punamustat puut, jotka ovat tasapainotettuja binäärisiä hakupuita.
• Näiden tavoin myös AVL-puut ovat tasapainotettuja.
• Kuten edellä todettiin, AVL-puita käsittelevä artikkeli ilmestyi jo vuonna 1962. Punamustat
puut esiteltiin 10 vuotta myöhemmin vuonna 1972.
• Siinä missä punamustien puiden tasapainotus perustuu väriattribuutin käyttöön, on AVL-puissa
tähän tarkoitukseen tarvittava tieto säilötty alipuun korkeusattribuuttiin.
jokaisella solmulla alipuiden korkeudet saavat erota toisistaan korkeintaan yhdellä.
• Kyseessä on selvästikin tavallisen binäärisen hakupuun laajennos: uutena attribuuttina
solmualkioilla on korkeus.
• Sovitaan, että pysäytys- eli NIL-solmujen korkeus on -1. Siten alimman tason datasolmujen
korkeutena on 0, ja yleisesti määritellään:
korkeus[x] = max(korkeus[vasen[x]], korkeus[oikea[x]]) + 1
• Seuraavalla sivulla esitetään esimerkki AVL-puusta.
13U AVL-puut
3
1
44
78
17
2
-1
0
-1
32
1
50
0
-1
-1
0
-1
48
-1
0
-1
Kuvaan merkityt numerot edustavat solmujen korkeuksia.
62
-1
88
-1
13U.1 AVL-puun korkeus
•
Lause: n-alkioisen AVL-puun korkeus on Ο(log2n).
Todistus: Merkitään n(h):lla h-korkuisen AVL-puun solmujen minimimäärää.
On helppo nähdä, että n(0) = 1 ja n(1) = 2.
Kun n ≥ 2, niin pienin mahdollinen h-korkuinen puu koostuu
(i) juuresta
(ii) AVL-puusta, jonka korkeus on h – 1 ja
(iii) AVL-puusta, jonka korkeus on h – 2
Täten n(h) = n(h – 1) + n(h – 2) + 1.
Koska väistämättä n(h – 1) > n(h – 2), niin n(h) > 2n(h – 2).
Tästä saadaan iteroimalla:
n(h) > 2n(h – 2)
⇔ n(h) > 4n(h – 4)
⇔ n(h) > 8n(h – 6)
⇔…
⇔ n(h) > 2in(h – 2i)
Kun nyt ratkaistaan h – 2i = 0, saadaan i = h/2 ja n(h) > 2h/2n(0) = 2h/2 ⋅ 1.
Tästä saadaan ottamalla 2-kantainen logaritmi molemmilta puolilta edelleen h/2 < log2n(h),
eli h < 2log2n(h), mistä väite seuraa.
13U.2 Solmun lisääminen AVL-puuhun
• Solmualkion lisääminen AVL-puuhun tapahtuu samoin kuin normaaliin binääriseen
hakupuuhun (tai punamustaan puuhun). Lisäyksen jälkeen kuljetaan sen aikana edetty polku
takaisin juureen ja päivitetään matkan varrelle osuvien solmujen korkeus-attribuutit
käyttämällä edellä annettua korkeuden laskukaavaa ja tarvittaessa tasapainottamalla puu.
• Esimerkki: lisätään aikaisemmin esitettyyn AVL-puuhun solmu, jossa avaimena on 54.
3
1
44
78
17
2
-1
0
-1
32
1
50
0
-1
-1
0
-1
48
-1
0
-1
62
-1
88
-1
13U.2 Solmun lisääminen AVL-puuhun
Havaitaan, että puu päätyy epätasapainoon juurisolmun oikean pojan 78 kohdalta
alkavasta alipuusta alkaen: vasemman alipuun korkeutena on 2, mutta oikean 0.
Ei kelpaa – puu on saatava täältä tasapainoon (alue merkitty kuvaan kolmiolla).
4
44
1
78
17
3
-1
0
-1
32
2
50
0
-1
-1
0
-1
1
48
-1
0
62
-1
54
88
-1
13U.2 Solmun lisääminen AVL-puuhun
Puun uudelleenjärjestäminen:
• Jos puu P on epätasapainossa, niin kuljetaan puussa ylöspäin niin kauan, kunnes törmätään
sellaiseen solmuun x, että sen isovanhempi z on epätasapainossa. Merkitään näiden väliin
jäävää x:n isäsolmua y:llä.
• Olkoon nyt (a, b, c) näiden kolmen solmun x, y, z välijärjestys.
• Suoritetaan rotaatiot, joilla solmusta b tulee kolmikon juurisolmu.
• Tämän jälkeen pitää solmujen x, y, ja z korkeus-attribuutin arvot laskea uudelleen (muiden
kohdalla ne eivät muutu).
• Jatketaan seuraavaksi puussa ylöspäin aina juureen asti ja tehdään tarvittavat tasapainotukset
ja korkeus-attribuuttien päivitykset kuten edellä.
• Esitellään seuraavaksi, millaisilta AVL-puiden kierto-operaatiot näyttävät.
• AVL-puiden kierto-operaatiot ovat joko yksin- tai kaksinkertaisia. Kaksinkertainen rotaatio
koostuu itse asiassa kahdesta kierrosta, joiden suunta on päinvastainen mutta joissa
keskussolmu vaihtuu kiertosuunnan vaihtuessa.
13U.2 Solmun lisääminen AVL-puuhun
• Yksinkertaiset rotaatiot:
1) Rotaatio vasemmalle
a=z
b=y
b=y
a=z
P0
c=x
c=x
P1
P0
P2
P3
P1
P2
P3
13U.2 Solmun lisääminen AVL-puuhun
• Yksinkertaiset rotaatiot:
2) Rotaatio oikealle
c=z
b=y
b=y
a=x
P3
a=x
P2
P0
c=z
P1
P0
P1
P2
P3
13U.2 Solmun lisääminen AVL-puuhun
• Kaksoisrotaatiot:
1) Kaksoisrotaatio oikealla alipuulla
a=z
b=x
c=y
a=z
c=y
P0
b=x
P3
P1
P2
P0
P1
P2
P3
13U.2 Solmun lisääminen AVL-puuhun
• Kaksoisrotaatiot:
2) Kaksoisrotaatio vasemmalla alipuulla
c=z
b=x
a=y
c=z
P3
a=y
P0
b=x
P0
P1
P2
P1
P2
P3
13U.2 Solmun lisääminen AVL-puuhun
Kun alkio 54 on lisätty, on solmu x (avainarvo 62) ensimmäinen, jonka isoisän z
kohdalla vallitsee epätasapaino
toipuminen: kaksoisrotaatio z:n vasemmalla alipuulla
4
44
2.
1
3
78
17
z
1.
-1
0
-1
32
2
50
0
y
-1
0
-1
1
48
-1
0
-1
x
62
-1
54
88
-1
13U.2 Solmun lisääminen AVL-puuhun
Esimerkin kaksoisrotaatio koostuu ensinnä vasemmasta kierrosta solmun y = 50
kohdalla, mitä seuraa oikea kierto solmun z = 78 kohdalla.
kokonaisvaikutus: lisätty solmu 54 nousee tasoa ylemmäs
3
44
1
2
62
17
x
-1
0
-1
32
1
50
1
y
-1
-1
0
-1
0
48
-1
-1
78
z
0
88
x
54
-1
-1
-1
13U.3 Solmun poistaminen AVL-puusta
• Solmu poistetaan AVL-puusta vastaavalla tavalla kuin tavallisesta binäärisestä hakupuustakin
(poistetaan siis joko halutun avainarvon sisältävä solmu itse tai sen seuraaja/edeltäjä)
• Oletetaan, että z on ensimmäinen epätasapainossa oleva solmu, joka tulee vastaan edettäessä
poistetusta solmusta kohti puun juurta.
• Oletetaan lisäksi, että y on solmun z lapsista se, jolla attribuutin korkeus arvo on suurempi
(tämän velisolmulla on siis pienempi korkeus).
• Edelleen oletetaan, että x on solmun y lapsista sellainen, että sen korkeus on vähintään yhtä
suuri kuin velisolmullaan.
• Puu on mahdollista tasapainottaa solmujen x, y ja z suhteen samoin kuin solmun lisäyksenkin
yhteydessä.
• Kierto-operaation suorittamisen jälkeen puu saattaa edelleen jäädä epätasapainoon, minkä
tähden on kuljettava korjauskohdasta eteenpäin aina juureen asti ja tehdä matkan varrella
tarpeelliset tasapainotukset ja korkeus-attribuuttien päivitykset.
• Tarkastellaan seuraavassa esimerkkiä, jossa AVL-puusta poistetaan arvon 32 sisältävä solmu.
Kyseessä on sama tilanne kuin edellä ennen uuden avaimen 54 lisäämistä.
13U.3 Solmun poistaminen AVL-puusta
• Esimerkki: Poistetaan avaimen 32 sisältävä solmu.
puu päätyy epätasapainoon juuren kohdalta.
3
3
44
1
17
32
78
0
-1
1
50
-1
0
88
0
-1
0
2
-1
48
-1
0
-1
78
17
2
-1
1
88
0
50
-1
-1
62
-1
44
0
-1
-1
48
-1
0
-1
62
-1
-1
13U.3 Solmun poistaminen AVL-puusta
•
Puuta joudutaan korjaamaan kaksoisrotaatiolla oikealla alipuulla siten, että z = a = 44,
x = b = 50 ja y = c = 78
Tarvittava kaksoisrotaatio koostuu ensinnä oikeasta rotaatiosta solmulla 78, ja sitä seuraa
vasen rotaatio solmun 44 kohdalla.
•
3
2
44
a=z
0
2
1
44
78
17
-1
c=y
-1
0
b=x
50
1
88
48
-1
-1
-1
62
-1
-1
0
a=z
48
1
0
62
78
0
c=y
88
1
-1
-1
17
b=x
50
-1
-1
-1
-1
-1
-1 -1
13U.3 Solmun poistaminen AVL-puusta
AVL-puiden käsittelyn kustannukset:
• Kierto-operaatiot tapahtuvat vakioajassa Θ(1)
• Kyselyoperaatiot avaimen haku, minimin etsintä, maksimin etsintä, seuraajan määrääminen ja
edeltäjän määrääminen saadaan jokainen suoritettua ajassa Ο(log2n), sillä puun korkeus
h = Ο(log2n).
• Myös lisäysoperaation aikavaativuus on luokkaa Ο(log2n), sillä
”normaalin” eli binääriseen hakupuuhun tehtävän lisäyksen kaltaisen osuuden
kompleksisuus on Ο(log2n) ja
korkeuksien päivitysten ja uudelleenjärjestämisten kompleksisuus on samoin Ο(log2n)
• Poistollakin on sama kompleksisuus Ο(log2n), sillä
”normaalin” poiston osuuden kustannus on Ο(log2n)
korkeuksien päivitysten ja uudelleenjärjestämisten kompleksisuus on samoin Ο(log2n)
• AVL-puiden käsittelyyn tarkoitettujen algoritmien pseudokoodit sivuutetaan tässä. Ne
esitetään tämän kurssin tarpeita ajatellen riittävästi AVL-puita käsittelevien TRAKLA-tehtävien
yhteydessä.
18 B-puut
•
B-puut esiteltiin ensimmäistä kertaa artikkelissa R. Bayer & E. M. McCreight: Organization and
maintenance of large ordered indexes, Acta Informatica 1 (1972), sivut 173 – 189.
Taustaa:
• Tietokoneen muistilaitteet voidaan karkeasti jakaa keskusmuistiin ja tukimuistiin (massamuistiin,
levymuistiin)
• Näistä keskusmuisti jakaantuu edelleen lukumuistiin ja työmuistiin.
• Lukumuisti (ROM, Read-Only Memory) sisältää koneen käynnistystoimenpiteet ja muita lyhyitä
toimintoja, kuten koneen käskykannan primitiiviset mikro-ohjelmat. Lukumuistin sisältö on pysyvää,
ja kun se kertaalleen on sijoitettu paikoilleen, se on vain luettavissa – ei päivitettävissä.
• Työmuisti (RAM, Random Access Memory) toimii ohjelmien ja niiden käyttämien tietojen
tallennuspaikkana tietokoneen toiminnan aikana. Työmuistia voidaan käyttää sekä kirjoittamiseen
että lukemiseen, eli sen sisältöä voidaan päivittää. Kun koneesta katkaistaan virta, työmuistin sisältö
menetetään.
• Levymuistin tallennuskapasiteetti on yleensä hyvin paljon suurempi kuin keskusmuistin, mutta
vastaavasti sen käyttäminen on paljon hitaampaa kuin keskusmuistin.
levymuisti koostuu päällekkäin pinotuista levyistä, joista kukin jakautuu sisäkkäisiin uriin, ja
urat puolestaan asteittaisiin sektoreihin
kaikkien levyjen luku- ja kirjoituspäät liikkuvat yhtä aikaa
levypakan päällekkäiset urat muodostavat sylinterin – yhden ja saman sylinterin sisältä tietojen
lukeminen tulee halvemmaksi (eli kestää lyhyemmän aikaa) kuin useilta eri urilta luettaessa (eri
levyjen luku- ja kirjoituspäät kohdistuvat kaikki yhteen sylinteriin kerrallaan eri levypinnoilla.
levymuisti on yleensä selvästi keskusmuistia halvempaa ostettaessa
18 B-puut
• Termillä saantiaika tarkoitetaan aikaa, joka kuluu luku- ja kirjoituspään sijoittamiseen oikealle
uralle ja sieltä oikean sektorin löytämiseen. Levyt pyörivät tietyllä nopeudella akselinsa ympäri,
joten levyn pyörimisnopeus vaikuttaa saantiaikaan (oikean sektorin löytämiseen menevään
aikaan). Kiintolevyjen saantiajat vaihtelevat usein välillä 6 – 14 millisekuntia (eli sekunnin
tuhannesosaa).
• Keskusmuistin normaali saantiaika on sen sijaan 50 – 100 nanosekuntia (eli sekunnin
miljardisosaa, nano = 10-9).
Täten pahimmassa tapauksessa saantiaika levyltä on
∗
∗
= 280 000 kertaa suurempi kuin keskusmuistista
• Seuraus: kun levyltä joudutaan lukemaan tietoja, kannattaa lukea samalla iso määrä tietoja
kerrallaan toistuvien hakujen aiheuttamien saantiaikojen välttämiseksi.
• Täten levyltä luetaan aina isohko määrä tietoja kerrallaan. Tällaista vakiokokoista levyltä
luettavaa jaksoa kutsutaan muistisivuksi. Tyypillinen sivun pituus vaihtelee välillä 211 – 214
tavua.
18 B-puut
• B-puut ovat tavallisen binäärisen hakupuun yleistyksiä.
• Ne sopivat hyvin sellaisiin hakemistoihin, joiden alkiojoukko on niin iso, ettei se mahdu
kerrallaan tietokoneen keskusmuistiin.
tavoitteena on aikaa vievien luku- ja kirjoitusoperaatioiden minimoiminen
• B-puiden solmuihin sijoitetaan binäärisestä hakupuusta poiketen yleensä useita avaimia, ja
samoin solmuilla voi olla useita lapsia (yhteensä solmun avainten lukumäärä + 1)
• Sen sijaan toisin kuin tavalliset binääriset hakupuut, B-puut ovat tasapainotettuja.
• Puun minimiaste t määrää sen, kuinka monta avainta puun yksittäiseen solmuun pitää
vähintään olla, ja montako avainta siihen voi enintään olla talletettuna.
tallennettavien alkioiden vähimmäismäärä: t – 1 avainta (solmulla oltava vähintään t lasta)
tallennettavien alkioiden enimmäismäärä: 2t – 1 avainta
poikkeuksen alkioiden vähimmäismäärästä muodostaa juurisolmu, jossa avaimia on 1..2t – 1
lisäksi triviaalin poikkeuksen vähimmäismäärästä muodostaa tyhjä B-puu, jonka juuressa
avaimia on 0
poikkeus lasten lukumäärään: lehtisolmuilla lapsien lukumäärä on 0
B-puun solmut:
• Jokaisessa B-puun solmussa siihen tallennetut avaimet ovat kasvavassa (ei-vähenevässä)
suuruusjärjestyksessä
• Solmuissa esiintyy myös lapsiosoittimia (avainten lukumäärä + 1)
18 B-puut
Määräämällä puulle sopivanlainen minimiaste saadaan aikaan seuraavaa:
• Puun jokaisen solmun avainjoukko mahtuu aina tiettyyn tilaan. Levyltä luetaan kerrallaan suuri
joukko avaimia, sillä – kuten edellä todettiin – ei ole kannattavaa lukea pelkästään yhtä avainta
levyltä lukeminen vie runsaasti aikaa verrattuna keskusmuistissa tehtäviin operaatioihin.
• Puu haarautuu voimakkaasti (sitä enemmän, mitä suurempi sen minimiaste on). Tämän takia
avainta etsittäessä joudutaan varsin vähän siirtymään solmusta toiseen.
• Esimerkki: B-puun solmulla, jolla on n avainta, on n + 1 lasta. Kaikki lehdet sijaitsevat samalla
etäisyydellä eli yhtä kaukana juuresta.
• M •
juuri[P]
• Q • T • X •
• D • H •
B C
E F
J K L
N P
R S
V W
Y Z
18 B-puut
Levyoperaatioista:
• B-puuta käsiteltäessä seuraavassa oletetaan, että dataa on niin paljon, ettei se kerrallaan
mahdu keskusmuistiin
• B-puiden algoritmit kopioivat valitun osan tiedoista levyltä keskusmuistiin. Kun halutut
muutokset on tehty, tallennetaan päivitetyt tiedot takaisin levylle.
• B-puiden algoritmit on suunniteltu siten, että vain vakiomäärä solmuja on keskusmuistissa
kerrallaan. Siten keskusmuistin koko ei rajoita käsiteltävien B-puiden kokoa.
Suoritusmalli:
• Oletetaan, että x on viittaus johonkin objektiin.
• Jos x:n viittaama objekti sijaitsee keskusmuistissa, voidaan sen attribuutteihin viitata suoraan
(esimerkiksi avain[x]).
• Jos kyseinen objekti sijaitsee levyllä, pitää ensin suorittaa operaatio LUE_LEVYLTÄ(x), joka lukee
x:n osoittaman objektin keskusmuistiin.
• Vasta silloin, kun x:n osoittama objekti on noudettu keskusmuistiin, sen sisältämiin tietoihin
päästään käsiksi ja tarvittaessa muuttamaan niitä.
• Operaatiolla TALLENNA_LEVYLLE(x) saadaan keskusmuistissa sijaitseva objekti x tallennettua
takaisin levylle (päivitysten tultua tehdyiksi).
18 B-puut
Esimerkki: Suuressa B-puussa voi yhdessä solmussa sijaita jopa 50 – 2 000 objektia (avainta)
juuri[P]
1 000
1 000
1 000
1 solmu, avaimia 1 000,
lapsisolmuja 1 001
1 000
1 000
1 000
1 001 solmua,
avaimia 1 001 000
lapsisolmuja 1 002 001
1 000
1 000
1 000
1 000
1 000
1 002 001 solmua, avaimia 1 002 001 000
• Seuraavassa oletetaan, että jokaiseen avaimeen liittyvä mahdollinen lisä- eli satelliittidata on
myös tallennettuna samaan solmuun kuin itse avainkin.
• B+-puu: Kaikki satelliittidata tallennetaan lehtiin, kun taas sisäsolmuihin tallennetaan ainoastaan
avaimet ja lapsiosoittimet.
• B+-puuta käsitellään tarkemmin tietokantoihin liittyvillä erikoiskursseilla.
18.1 B-puun määritelmä
1. Kuhunkin yksittäiseen solmuun x liittyvät tiedot:
(i) Attribuutti n[x] sisältää tiedon solmuun x tallennettujen avainten lukumäärästä.
(ii) Solmuun x sijoitetut avaimet on tallennettu kasvavaan (ei-vähenevään) järjestykseen:
avain1[x] ≤ avain2[x] ≤ … ≤ avainn[x][x]
(iii) Attribuutti lehti[x] sisältää totuusarvon tosi, jos solmu x on lehtisolmu, ja muulloin arvon epätosi.
2. Lisäksi jokainen solmu (paitsi lehtisolmut) sisältävät lisäksi n[x] + 1 kappaletta osoittimia:
c1[x], c2[x], c3[x], …, cn[x][x], cn[x] + 1[x]
Kyseiset osoittimet, ci :t, osoittavat solmun x järjestyksessä i. lapsisolmuun.
Koska lehtisolmuilla ei ole lapsia, niiden ci-arvot ovat määrittelemättömiä.
3. Merkitään ki:llä solmua, joka on tallennettu sellaiseen alipuuhun, jonka juurena esiintyy solmu ci[x].
Tällöin on voimassa:
k1 ≤ avain1[x] ≤ k2 ≤ avain2[x] ≤ … ≤ avainn[x][x] ≤ kn[x] + 1
Toisin sanoen, kaikki solmun i. lapsiosoittimen takaa aukeavan alipuun sisältämät avaimet ovat
suurempia tai yhtä suuria kuin solmun x i – 1. avain (kun i > 1) sekä pienempiä tai yhtä suuria kuin
solmun x i. avain (kun i < n[x] + 1).
18.1 B-puun määritelmä
4. Kaikki lehdet ovat samalla etäisyydellä juuresta; puun korkeutta ilmaisee merkintä h.
5. B-puulle on määriteltynä minimiaste t (t ≥ 2):
(i) Jokaisessa solmussa (paitsi juuressa) on oltava vähintään t – 1 avainta. Siten jokaisella
sisäsolmulla on oltava vähintään t lapsisolmua. Mikäli kyseessä ei ole tyhjä B-puu, pitää
juureen olla sijoitettuna vähintään yksi avain.
(ii) Jokaisessa solmussa voi olla enintään 2t – 1 avainta. Täten solmulla voi olla korkeintaan 2t
kappaletta lapsia. Solmu on täynnä, mikäli se sisältää tarkalleen 2t – 1 avainta.
•
•
Yksinkertaisin mahdollinen B-puu on sellainen, että t = 2. Tällöin jokaisella sisäsolmulla on joko
2, 3 tai 4 lasta. Siten tällaista puuta kutsutaan myös 2-3-4-puuksi.
Lause 18.1: Jos n ≥ 1, niin sellaisen n-avaimisen B-puun, jonka minimiaste t ≥ 2, korkeus on
h ≤ logt
Todistus: Pienin mahdollinen B-puu on seuraavanlainen:
Juureen on tallennettu yksi alkio.
Jokaisessa muussa solmussa on minimaalinen määrä eli t – 1 alkiota.
Etäisyydellä i olevalla tasolla (juuresta laskettuna) on 2ti – 1 solmua (solmuilla on t lasta, paitsi
juurella aina 2 riippumatta t:n valinnasta, kunhan n > 2).
Täten
n ≥ 1 + (t – 1) ∑ 2 = 1 + 2(t – 1) ∑
= 1 + 2(t – 1) = 2th – 1.
Nyt
≥ th ⇔ h ≤ logt
.
18.1 B-puun määritelmä
• Lemma: Jos x ≠ 1, niin
∑ =
Todistus: Kaikilla x ≠ 1 ja n ≥ 0:
∑ =
x ∑ =
(x – 1) ∑ =
x0
+
x1
+
x2
+
…
+
xn
x1
+
x2
+
…
+
xn
-1
ja
+
xn + 1
+
xn + 1
(vähennettiin alemmasta summasta ylempi).
18.2 B-puun perusoperaatiot
HAKU, LUONTI JA LISÄYS
Sopimus: Puun juuri on aina keskusmuistissa, joten operaatiota LUE_LEVYLTÄ(juuri[P]) ei
milloinkaan tarvitse suorittaa. Sen sijaan operaatio TALLENNA_LEVYLLE(juuri[P]) on
tarpeellinen, mikäli juurisolmuun tehdään muutoksia.
18.2 B-puun perusoperaatiot
Haku B-puusta
• Muistuttaa melkoisesti hakua binäärisestä hakupuusta.
• Nyt joudutaan kuitenkin suorittamaan hakua myös solmun sisällä, koska B-puun solmussa voi
sijaita useita avaimia.
Syöte ja tuloste hakua suoritettaessa (oletetaan, että puusta haetaan avainta k):
•
•
•
•
Syötteenä annetaan parametri x, joka viittaa (ali)puun juureen.
Lisäksi syötteenä annetaan haettava avain k.
Ylimmän tason kutsu: HAE_B-PUUSTA(juuri[P], k)
Jos etsittävä avain k esiintyy puussa, palautetaan järjestetty pari (y, i), missä y on B-puun solmu
ja i on sellainen indeksi, jolle on voimassa
avaini[y] = k
• Ellei etsittyä avainta k löydy puusta, palautetaan arvo NIL.
• Seuraavaksi esitetään B-puusta hakua suorittavan algoritmin HAE_B-PUUSTA pseudokoodi.
18.2 B-puun perusoperaatiot
HAE_B-PUUSTA(x, k)
1 i := 1
2 WHILE i ≤ n[x] AND k > avaini[x] DO
3
i := i + 1
4 IF i ≤ n[x] AND k = avaini[x]
5
THEN RETURN (x, i)
6 IF lehti[x]
7
THEN RETURN NIL
8
ELSE LUE_LEVYLTÄ(ci[x])
9
RETURN HAE_B-PUUSTA(ci[x], k)
Algoritmin toimintaperiaate:
luetaan nykyisestä solmusta x avaimia niin pitkään, kunnes joko
1) kohdataan ensimmäinen avain, jonka arvo on suurempi tai yhtä suuri kuin etsittävä avain k
tai
2) solmun x kaikki avaimet on jo ehditty tutkia, jolloin k oli kaikkia näitä suurempi
tapauksessa 1) tutkitaan seuraavaksi, oliko solmun x i. avain arvoltaan k
jos oli, palautetaan järjestetty pari (x, i)
ellei, jatketaan hakua x:n i. lapsisolmusta, jos x ei ole lehti, ja muussa
tapauksessa haun todetaan epäonnistuneen palauttamalla NIL-osoitin
tapauksessa 2) jatketaan hakua solmun x viimeisestä lapsisolmusta, mikäli x ei ole lehtisolmu. Jos x
on lehti, haku on epäonnistunut ja palautetaan NIL-osoitin.
18.2 B-puun perusoperaatiot
Algoritmin kompleksisuus:
Levyoperaatioiden kustannus on Ο(h) = Ο(logtn). Pahimmassa tapauksessa etsintää
joudutaan jatkamaan aina lehtitasolle asti, jolloin puun jokaisella tasolla juurta lukuun
ottamatta suoritetaan yhden solmun haku levyltä.
Kokonaissuoritusaika: Koska n[x] < 2t, niin suoritusaika on Ο(th) = Ο(t logtn), sillä jokaisella
tasolla joudutaan tutkimaan yksi solmu, ja pahimmassa tapauksessa
sen kaikki avaimet joudutaan selaamaan läpi (oletuksena on, että
solmujen avaimia selataan lineaarihaulla).
• Esimerkki: Etsitään seuraavassa kuvassa esitetystä B-puusta alkiota R.
• M •
juuri[P]
• Q • T • X •
• D • H •
B C
E F
J K L
N P
R S
V W
Y Z
Haun aikana joudutaan tutkimaan vain esitetyn puun punaisella värjätyt solmut.
18.2 B-puun perusoperaatiot
Tyhjän B-puun perustaminen
•
•
Algoritmi PERUSTA_B-PUU(P) on (konstruktori-)operaatio, joka luo uuden tyhjän B-puun P.
LUO_SOLMU on vakioaikainen (Ο(1)) operaatio, joka varaa tilaa levyltä juurisolmua varten.
PERUSTA_B-PUU(P)
1 x := LUO_SOLMU()
2 lehti[x] := tosi
3 n[x] := 0
4 TALLENNA_LEVYLLE(x)
5 juuri[P] := x
Algoritmin PERUSTA_B-PUU kompleksisuus on vakioaikainen: kaksi vakioaikaista levyoperaatiota ja kolme asetuslausetta.
B-puuhun lisääminen
•
•
•
•
B-puuhun lisääminen on hankalampaa kuin tavalliseen binääriseen hakupuuhun lisääminen, jossa uusi solmu lisätään
aina uudeksi lehdeksi.
B-puuhun avain lisätään sitä vastoin jo olemassa olevaan lehtisolmuun.
Ongelmatilanne: Täyteen solmuun ei enää pystytä lisäämään avaimia (solmu on täynnä, jos se sisältää
jo 2t – 1 avainta).
Ratkaisu: Täysi solmu halkaistaan seuraavasti:
avain1[y], …, avaint – 1[y], avaint[y], avaint + 1[y], …, avain2t – 1[y]
mediaani
t – 1 kappaletta
t – 1 kappaletta
18.2 B-puun perusoperaatiot
• Halkaistavan solmun y alkuosan t – 1 avainta ja loppuosan t – 1 avainta muodostavat uudet
solmut, ja y:n keskimmäinen avain eli avaint[y] siirretään vanhempaansa, jonka sekä avaimien
että lasten lukumäärä kasvaa nyt yhdellä.
• Kannattaa huomioida, että etsittäessä oikeaa sijoituspaikkaa uudelle lisättävälle avaimelle
lehtitasolta jokainen vastaantuleva täysi solmu joudutaan halkaisemaan.
Lapsisolmun halkaiseminen
Syöte:
• Ei-täysi isäsolmu x (sinne voidaan sijoittaa vielä ainakin yksi avain lisää)
• Sellaiset solmu y ja indeksi i, että y = ci[x], ja lisäksi solmu y on täysi (ei mahdu enää lisäavaimia)
Toiminta:
• Solmu y halkaistaan edellä kuvatulla tavalla.
• Solmua x joudutaan järjestelemään uudelleen siten, että sille luodaan uusi lapsisolmu.
• Mikäli juurisolmu joudutaan halkaisemaan, luodaan ensiksi uusi juurisolmu, jonka lapseksi vanha
juurisolmu asetetaan.
• Seuraavaksi esitetään hahmotelma lapsisolmun halkaisualgoritmin toiminnasta.
18.2 B-puun perusoperaatiot
Lapsisolmun halkaiseminen:
x
• • • N • W • • •
• • • N • S • W • • •
x
i
i
i+1
y
y
• P • Q • R • S • T • U • V•
• P • Q • R •
z
• T • U • V •
• Ylempänä näkyvässä hahmotelmassa ollaan avainta lisättäessä edetty solmuun y, jonka
havaitaan olevan täynnä.
solmun ensimmäiset kolme avainta P, Q ja R (tässä t = 4) jäävät paikoilleen solmuun y
solmun keskimmäinen eli mediaaniavain S nousee tasoa ylöspäin isäsolmuunsa
solmun y kolmea viimeistä avainta varten perustetaan uusi solmu z, jonne ne viedään
kaikkine mahdollisine viittauksineen ja satelliittidatoineen.
• Seuraavaksi esitellään lapsisolmun halkaisun suorittavan algoritmin pseudokoodi.
18.2 B-puun perusoperaatiot
HALKAISE_B-PUUN_LAPSISOLMU(x, i, y)
1 z := LUO_SOLMU()
2 lehti[z] := lehti[y]
3 n[z] := t – 1
4 FOR j := 1, 2, …, t – 1 DO
5
avainj[z] := avainj + t[y]
6 IF NOT lehti[y]
7
THEN FOR j := 1, 2, …, t DO
8
cj[z] := cj + t[y]
9 n[y] := t – 1
10 FOR j := n[x] + 1, n[x], …, i + 1 DO
11
cj + 1[x] := cj[x]
12 ci + 1[x] := z
13 FOR j := n[x], n[x] – 1, …, i DO
14
avainj + 1[x] := avainj[x]
15 avaini[x] := avaint[y]
16 n[x] := n[x] + 1
17 TALLENNA_LEVYLLE(x)
18 TALLENNA_LEVYLLE(y)
19 TALLENNA_LEVYLLE(z)
18.2 B-puun perusoperaatiot
Algoritmin toimintaperiaate:
• Rivit 1 – 8: Alustetaan uusi solmu z. Solmu z merkitään lehdeksi, jos halkaistava solmu y on
sellainen. Solmun z avainten lukumääräksi asetetaan t – 1, ja siihen kopioidaan y:n
t – 1 suurinta avainta. Jos kyseessä ei ole lehtisolmu, myös y:n t ylintä lapsiosoitinta
kopioidaan solmuun z.
• Rivi 9: Asetetaan t – 1 myös solmun y uudeksi avainten lukumääräksi.
• Rivit 10 – 16: Näillä riveillä siirretään x:n jälkimäisen puolikkaan lapsiosoittimia yksi askel oikealle
ja asetetaan uusi solmu z solmun x lapseksi. Lisäksi x:n jälkimmäisen puolikkaan
avainarvoja siirretään yksi askel oikealle ja lisätään (entisen) solmun y
mediaanialkio (järjestyksessä t. alkio) solmuun x.
• Rivit 17 – 19: Kirjoitetaan muutetut solmut x, y ja z levylle.
Lapsisolmun halkaisualgoritmin kompleksisuus:
• Algoritmin aikavaativuus määräytyy silmukoiden perusteella, joissa tehtävien kierrosten määrää
voidaan rajoittaa lausekkeella Θ(t). Rivien 1 sekä 17 – 19 levyoperaatiot ovat vakioaikaisia, kuten
myös silmukoissa suoritettavat (rivit 5, 8, 11 ja 14) ja niiden ulkopuolelle (rivit 2, 3, 9, 12, 15 ja
16) jäävät lauseet.
• Seuraavaksi esitellään ylimmän tason algoritmi LISÄÄ_B-PUUHUN, jolla voidaan tuoda puuhun
uusi avain. Algoritmissa huomioidaan myös tilanne, jossa juurisolmu joudutaan halkaisemaan.
• Algoritmin tarvitsema alialgoritmi LISÄÄ_EI-TÄYTEEN_B-PUUHUN esitellään heti tämän perään.
18.2 B-puun perusoperaatiot
LISÄÄ_B-PUUHUN(P, k)
1 r := juuri[P]
2 IF n[r] = 2t – 1 /* Onko juurisolmu jo täyttynyt? */
3
THEN s := LUO_SOLMU()
4
juuri[P] := s
5
lehti[s] := epätosi
6
n[s] := 0
7
c1[s] := r
8
HALKAISE_B-PUUN_LAPSISOLMU(s, 1, r)
9
LISÄÄ_EI-TÄYTEEN_B-PUUHUN(s, k)
10 ELSE LISÄÄ_EI-TÄYTEEN_B-PUUHUN(r, k)
• Esimerkki täyden juuren halkaisusta:
juuri[P]
juuri[P]
r
• H •
• A • D • F • H • L • N • P•
• A • D • F •
• L • N • P •
18.2 B-puun perusoperaatiot
LISÄÄ_EI-TÄYTEEN_B-PUUHUN(x, k)
1 i := n[x]
2 IF lehti[x]
3
THEN WHILE i ≥ 1 AND k < avaini[x] DO
4
avaini + 1[x] := avaini[x]
5
i := i – 1
6
avaini + 1[x] := k
7
n[x] := n[x] + 1
8
TALLENNA_LEVYLLE(x)
9
ELSE WHILE i ≥ 1 AND k < avaini[x] DO
10
i := i – 1
11
i := i + 1
12
LUE_LEVYLTÄ(ci[x])
13
IF n[ci + 1[x]] = 2t – 1
14
THEN HALKAISE_B-PUUN_LAPSISOLMU(x, i, ci[x])
15
IF k > avaini[x]
16
THEN i := i + 1
17
LISÄÄ_EI-TÄYTEEN_B-PUUHUN(ci[x], k)
18.2 B-puun perusoperaatiot
Algoritmin toimintaperiaate:
• Rivi 1: alustetaan laskuri i solmun x avainten lukumäärällä
• Rivi 2: testataan, ollaanko jo saavuttu lehtisolmuun
• Rivit 3 – 8: Tarkastellaan tapausta, jolloin solmu x on lehti. Tällöin avain k tallennetaan kyseiseen
solmuun
• Rivi 9 – 12: Paraikaa tarkasteltava solmu x ei ole lehti. Valitaan x:n lapsiosoittimista se, jota pitkin
lisäämisen hakupolku jatkuu eteenpäin k:n perusteella.
• Rivit 13 – 16: Tutkitaan, onko valittu solmu täynnä vai ei. Mahdollinen täysi solmu halkaistaan ja
ratkaistaan, kummalta puolelta halkaistun solmun mediaania lisäyspaikan hakua
jatketaan.
• Rivit 17: Kutsutaan rekursiivisesti lisäysalgoritmia ei-täydelle juurisolmulle sille x:n lapsisolmulle,
jonka kautta k:n lopullinen sijoituspaikka löytyy.
Lisäysalgoritmin kompleksisuus:
• Jokainen algoritmin LISÄÄ_EI-TÄYTEEN_B-PUUHUN kutsu tekee vain vakiomäärän luku- ja
kirjoitusoperaatioita levyltä/levylle.
• Algoritmin LISÄÄ_B-PUUHUN suorituksen aikana tehdään Ο(h) = Ο(logtn) levyoperaatiota.
• Kokonaissuoritusaika: Ο(th) = Ο(tlogtn).
18.2 B-puun perusoperaatiot
Esimerkki: Lisätään seuraavaan B-puuhun järjestyksessä avaimet B, Q, L ja F. Puun minimiaste t = 3.
G M P X
A C D E
J K
N O
R S T U V
Y Z
Vaihe 1: Lisätään B – lisäys onnistuu suoraan vasemmanpuoleisimpaan lehteen
ainoastaan avaimia D ja E joudutaan siirtämään eteenpäin
G M P X
A B C D E
J K
N O
R S T U V
Y Z
18.2 B-puun perusoperaatiot
Vaihe 2: Lisätään Q – kyseinen avain kuuluisi toiseksi viimeiseen lehteen, joka on nyt
halkaistava ennen lisäystä
avain T joudutaan nostamaan solmusta juureen juurisolmu täyttyy
Q päätyy halkaistavaan solmuun, sillä se kuuluu ennen mediaanialkiota S
G M P X
A B C D E
J K
N O
R S T U V
Y Z
G M P T X
A B C D E
J K
N O
Q R S
U V
Y Z
18.2 B-puun perusoperaatiot
Vaihe 3: Lisätään L – kyseinen avain kuuluu toiseen lehteen, jossa on kylläkin tilaa, mutta
juurisolmu on ehtinyt täyttyä
ensi töiksi joudutaan juurisolmu halkaisemaan
tämän jälkeen L sijoitetaan paikalleen lehtisolmuun, johon se kuuluu
G M P T X
A B C D E
J K
Q R S
N O
U V
Y Z
P
G M
A B C D E
J K L
T X
N O
Q R S
U V
Y Z
18.2 B-puun perusoperaatiot
Vaihe 4: Lisätään F – kyseinen avain kuuluisi ensimmäiseen lehteen, joka on täyttynyt
kyseinen solmu joudutaan halkaisemaan, ja C siirtyy tasoa ylemmäs
tämän jälkeen F sijoitetaan halkaisun tuloksena syntyneeseen uuteen
solmuun
P
G M
A B C D E
J K L
T X
Q R S
N O
U V
Y Z
P
C G M
A B
D E F
J K L
T X
N O
Q R S
U V
Y Z
18.3 Avaimen poistaminen B-puusta
•
•
•
•
•
Algoritmi POISTA_AVAIN_B-PUUSTA poistaa avaimen k sellaisesta alipuusta, jonka juurena esiintyy x.
Algoritmi on kirjoitettu siten, että aina kun sitä kutsutaan solmulla x, on kyseisessä solmussa vähintään
minimiasteen t verran avaimia (poikkeuksena kuitenkin juuri).
Määritelmän mukaan B-puussa pitää jokaisessa solmussa sijaita vähintään t – 1 avainta. Edellisessä
kohdassa esitetyn tiukemman vaatimuksen ansiosta riittää, että poistettaessa avainta kuljetaan puussa
yksistään alaspäin (KYSYMYS: Millä perusteella?). Tiukentamisesta seuraa kuitenkin joitakin
ylimääräisiä toimenpiteitä.
Mikäli juurisolmu x tulee tyhjäksi, se poistetaan, ja sen ainoasta lapsesta c1[x] tulee uusi juuri. Samalla
puun korkeus pienenee.
Koska poistoalgoritmi on verrattain pitkä ja monimutkainen, sen pseudokoodia ei esitetä tässä, vaan
tyydytään ainoastaan kuvaamaan periaatteet, miten poisto etenee eri tapauksissa.
Solmun poistamisen periaatteet
1. Jos poistettava avainta k ei löydy solmusta x, siirrytään puussa alaspäin sopivaan alipuuhun
seuraamalla lapsiosoitinta ci[x] ja jatketaan etenemistä rekursiivisesti. Jos osoittimen ci[x]
osoittamassa solmussa on vain t – 1 avainta, suoritetaan seuraavista joko toimenpide (a) tai (b)
sen takia, että solmuun tulisi vähintään t avainta.
(a) Jos ci[x]:ssä on vain t – 1 avainta mutta sen sisaruksella on vähintään t avainta, lainataan
ci[x]:lle yksi avain tämän isäsolmulta x ja palautetaan sieltä lainatun avaimen tilalle yksi avain
siltä ci[x]:n sisarukselta, jossa avaimia on vähintään t kappaletta. Mahdollinen lapsiviittaus
siirretään samalla.
18.3 Avaimen poistaminen B-puusta
(b) Jos sekä ci[x]:ssä että sen sisaruksilla on vain t – 1 avainta, limitetään solmu ci[x] toisen
sisaruksensa kanssa ja lisätään vielä isäsolmulta x yksi avain limityksessä muodostuneen
solmun mediaaniksi.
2. Mikäli k on lehtisolmussa, tuhoa avain k sieltä.
3. Jos k sijaitsee jossain sisäsolmussa x, toimitaan seuraavasti:
(a) Jos avainta k edeltävässä lapsessa y on vähintään t avainta, etsitään k:n edeltäjä k’ kyseisestä
alipuusta. Avain k’ tuhotaan rekursiivisesti alipuustaan, ja se sijoitetaan alun perin
poistettavaksi tarkoitetun avaimen k tilalle.
(b) Jos avainta k seuraavassa lapsessa z on vähintään t avainta, etsitään k:n seuraaja k’
kyseisestä alipuusta. Avain k’ tuhotaan jälleen rekursiivisesti alipuustaan kuten edellä, ja se
sijoitetaan alun perin poistettavaksi tarkoitetun avaimen k tilalle.
(c) Jos kummassakin x:n lapsisolmussa y ja z on vain t – 1 avainta, muodostetaan uusi solmu
limittämällä solmut y ja z, liitetään muodostuneeseen solmuun avainarvo k ja poistetaan k
rekursiivisesti.
• Poiston kompleksisuus on Ο(t logtn), ja levyoperaatioita tehdään Ο(logtn).
18.3 Avaimen poistaminen B-puusta
Esimerkki: Poistetaan seuraavasta B-puusta järjestyksessä avaimet F, M, G, D ja B. Kyseessä on
samainen puu, joka saatiin aikaan lisäysoperaatiota käsitelleen esimerkin päätteeksi.
Puun minimiaste t = 3.
P
C G M
A B
D E F
J K L
T X
N O
Q R S
U V
Y Z
Vaihe 1: Poistetaan F – avain sijaitsee lehdessä (ensiksi kahdesti tapaus 1, sitten tapaus 2)
hakupolun varrelle osuvissa solmuissa juuresta eteenpäin (merkitty kuvaan
punaisella värillä) ≥ 3 avainta
poistetaan F suoraan nykyisestä sijaintipaikastaan ilman lisätoimenpiteitä
P
T X
C G M
A B
D E ■
J K L
N O
Q R S
U V
Y Z
18.3 Avaimen poistaminen B-puusta
P
T X
C G M
A B
D E
J K L
N O
Q R S
U V
Y Z
Vaihe 2: Poistetaan M – avain sijaitsee sisäsolmussa (ensiksi tapaus 1, sitten tapaus 3a ja lopulta 2)
hakupolun varrelle osuvissa solmuissa juuresta eteenpäin ≥ 3 avainta
avainta M edeltävässä lapsisolmussa ≥ t = 3 avainta: etsitään kyseisestä
alipuusta M:n edeltäjä L, joka kopioidaan M:n paikalle ja poistetaan lehdestä
P
T X
C G L
A B
D E
J K ■
N O
Q R S
U V
Y Z
18.3 Avaimen poistaminen B-puusta
P
T X
C G L
A B
D E
J K
N O
Q R S
U V
Y Z
Vaihe 3: Poistetaan G – tämäkin avain kuten edellä M sijaitsee sisäsolmussa (tapaukset 1, 3c, 2)
hakupolun varrelle osuvissa lehtisolmuissa kummassakin vain 2 avainta
limitetään solmut DE ja JK keskenään ja tuodaan sen mediaanialkioksi
isäsolmusta poistettava avain G, joka nyt saman tien poistetaan lehdestä
P
T X
C L
A B
D E G J K
N O
Q R S
U V
Y Z
18.3 Avaimen poistaminen B-puusta
P
T X
C L
A B
Q R S
N O
D E J K
U V
Y Z
Vaihe 4: Poistetaan D – tämä avain sijaitsee lehtisolmussa
hakupolun varrelle osuvassa sisäsolmussa ja sen ainoassa sisaruksessa
kummassakin kuitenkin vain 2 avainta (aluksi tapaus 1b)
limitetään solmut CL ja TX keskenään ja tuodaan sen mediaanialkioksi
isäsolmusta poistettava avain P, jolloin puu kutistuu ja uudeksi juureksi CLPTX
lopuksi poistetaan D lehdestä DEJK ilman pulmia (tapaus 2)
■
C
A B
■ E J K
L
N O
P
T
X
Q R S
U V
Y Z
18.3 Avaimen poistaminen B-puusta
C
A B
L
P
T
Q R S
N O
E J K
X
U V
Y Z
Vaihe 5: Poistetaan B – tämäkin avain sijaitsee lehtisolmussa (aluksi tapaus 1a)
hakupolun varrelle osuvassa lehtisolmussa vain 2 avainta, mutta sen ainoalla
sisaruksella – solmulla EJK – on avaimia minimiasteen t = 3 verran.
tuodaan solmuun AB täytteeksi isäsolmusta sen ensimmäinen avain C, jonka
paikan isäsolmussa ottaa tämän seuraaja E, joka menettää paikkansa
toisessa lehtisolmussa
lopuksi poistetaan B täydentyneestä lehdestä ABC ilman pulmia (tapaus 2)
E
A ■ C
■ J K
L
N O
P
T
X
Q R S
U V
Y Z
19X Binomikeko
• Binomikeot esiteltiin ensimmäistä kertaa artikkelissa R. Bayer: Symmetric binary B-trees: data
structure and maintenance algorithms, Acta Informatica 1 (1972), sivut 290 – 306.
• Binomikeot ovat minimikekoja, jotka ovat limitettävissä.
• Niille on määritelty prioriteettijonon operaatiot.
Operaatiot:
•
•
•
•
LUO_KEKO(): luo tyhjän binomikeon
LISÄÄ(H, x): lisää alkion x binomikekoon H
MINIMI(H): palauttaa viittauksen binomikeon H siihen alkioon, jonka avain on pienin
POISTA_MINIMI(H): poistaa binomikeosta sen pienimmän alkion palauttamalla samalla
osoittimen kyseiseen alkioon
• PIENENNÄ_AVAINARVOA(H, x, k): pienennetään binomikeossa H sijaitsevaan solmuun x
tallennettua avainarvoa arvoon k. Oletuksena on, ettei
syötteenä annettava k ole nykyistä avainarvoa isompi.
• POISTA(H, x): poistaa solmualkion x binomikeosta H
• UNIONI(H1, H2): perustaa uuden binomikeon, joka sisältää kekojen H1 ja H2 alkiot
19X Binomikeko
• Seuraavassa taulukossa on esitelty eri operaatioiden pahimman tapauksen suoritusaikoja
tavalliselle minimikeolle sekä binomikeolle:
Operaatio
Keko
Binomikeko
Θ(1)
Θ(1)
Θ(log2n)
Ο(log2n)
Θ(1)
Ο(log2n)
Θ(log2n)
Θ(log2n)
Θ(n)
Ο(log2n)
PIENENNÄ_AVAINARVOA**
Θ(log2n)
Θ(log2n)
POISTA**
Θ(log2n)
Θ(log2n)
LUO_KEKO
LISÄÄ
MINIMI
POISTA_MINIMI
UNIONI*
*) Operaation MUODOSTA_KEKO kustannus on Θ(n).
**) Alkion paikan pitää olla tiedossa etukäteen.
19X.1 Binomipuut
• Binomikeko muodostuu binomipuista.
• Binomipuu Bk on järjestetty puu, joka määritellään rekursiivisesti seuraavalla tavalla:
B0 koostuu yhdestä solmusta
Bk (k > 0) koostuu kahdesta juurisolmuistaan toisiinsa linkitetystä Bk – 1-binomipuusta.
B0
Bk
Bk – 1
Bk – 1
• Binomipuun Bk korkeus on k.
• Seuraavassa ovat nähtävissä binomipuut B0, B1, B2, B3 ja B4 vasemmalta oikealle.
B1
B2
B3
B0
B4
19X.1 Binomipuut
• Lemma: Tarkastellaan binomipuuta Bk.
(a) Binomipuussa on 2k solmua.
(b) Puun juuren lasten lukumäärä on k. Lisäksi, jos lapset numeroidaan vasemmalta
oikealle k – 1, k – 2, …, 1, 0, niin solmu i (0 ≤ i ≤ k – 1) on binomipuun Bi juuri.
Todistus: (a) Induktiolla k:n suhteen.
i) Väite pitää paikkansa, kun k = 0, sillä puussa B0 on yksi solmu.
ii) Oletetaan, että väite pitää paikkansa puulla Bk – 1. Tästä kuitenkin seuraa,
että väite on voimassa myös puulla Bk, sillä koska Bk muodostuu kahdesta
Bk – 1-puusta, on sen solmujen lukumäärä
2k – 1 + 2k – 1 = 2 ⋅ 2k – 1 = 2(k – 1) + 1 = 2k. 
(b) Samoin induktiolla k:n suhteen.
i) Väite on voimassa arvolla k = 0, sillä puussa B0 on ainoastaan juurisolmu,
jolla ei selvästikään ole yhtään lasta.
ii) Koska Bk muodostuu kahdesta yhteen linkitetystä Bk – 1-puusta, on Bk :n
juurella yksi lapsi enemmän kuin Bk – 1-puun juurella. Induktio-oletuksen
mukaan Bk – 1:n juurella on k – 1 lasta, kun k > 0, joten Bk :lla on siten k
lasta. Binomipuun B1 ainoa lapsi on B0.
19X.1 Binomipuut
Induktio-oletuksen mukaan lisäksi puun Bk – 1 juuren lapset ovat vasemmalta
lukien järjestyksessä Bk – 2, Bk – 3, Bk – 4, …, B2, B1, B0. Linkitettäessä kaksi
Bk – 1-puuta (k > 1) yhteen, tulevat toisen Bk – 1-puun juuren lapset linkityksen
tuloksena muodostuneen Bk -puun juuren lapsiksi. Lisäksi toinen Bk – 1-puu
päätyy vastikään syntyneen Bk -puun lapseksi. 
Seuraus: n-solmuisen binomipuun solmujen maksimaalinen lasten määrä on log2n.
Todistus: Solmujen määrä n = 2k, joten k = log2n. Koska juurella on eniten lapsia, ja
juuren lasten lukumäärä on k, väite seuraa tästä. 
Binomikeko
• Binomikeko H koostuu joukosta binomipuita, jotka täyttävät binomikeko-ominaisuudet:
(1) Kukin keon H binomipuista on minimikekojärjestyksessä, eli jokaisen solmun avain on
vähintään solmun isäsolmussa sijaitsevan avainarvon suuruinen (kunkin puun pienin avain
on oltava juuressa).
(2) Määritellään k binomipuun Bk asteeksi. Astetta k olevia binomipuita voi esiintyä
binomikeossa H korkeintaan yksi.
19X.1 Binomipuut
• Luvun n binääriesityksen pituus on log2n + 1 bittiä, ja se on muotoa:
<blog2n, blog2n – 1, …, b2, b1, b0>.
Siten n = ∑

2 .
• Esimerkki: Luvun 11 binääriesitys on 1011, joten
1110 = 1 ⋅ 20 + 1 ⋅ 21 + 0 ⋅ 22 + 1 ⋅ 23
• Tarkastellaan n-alkioista binomikekoa H. Koska binomikekoon voi kuulua vain enintään yksi
tiettyä astetta oleva binomipuu ja puun Bk koko on 2k, muodostuu luvun n binääriesityksen ja
binomipuun H välille seuraavanlainen yhteys:
Puu Bk on binomikeossa H ⇔ bitti bk = 1
• Edellisen perustella n-alkioinen binomikeko H sisältää enintään log2n + 1 binomipuuta.
• Koska binomipuun Bk korkeus on k ja n:n binääriesitys on muotoa
 
n = ∑ 2,
niin H:n korkeimman puun korkeus on log2n.
19X.1 Binomipuut
• Esimerkki: Luvun 1110 binääriesitys on
<b3, b2, b1, b0> = 1011,
joten 11-alkioinen binomikeko muodostuu puista B0, B1 ja B3.
alku[H]
B0
10
B1
6
1
8
12
11
25
• Binomikeon esitysmuoto
Vasemmanpuoleisin lapsi ja oikea sisarus -rakenne
17
14
35
29
B3
19X.1 Binomipuut
• Solmualkion x attribuutit:
avain[x] – solmun avainarvo
mahdollinen lisädata (satelliittidata)
vanhempi[x] – osoitin isäsolmuun
lapsi[x] – osoitin vasemmanpuoleisimpaan lapsisolmuun
sisarus[x] – osoitin oikeanpuoleiseen sisarukseen
aste[x] – tieto x:n lasten lukumäärästä
• Huomioitavaa:
Jos solmu x on juuri, niin vanhempi[x] = NIL
Jos solmu x on isänsä kaikkein oikeanpuoleisin lapsi, niin silloin sisarus[x] = NIL
Lisäksi koko binomikeolle H on määritelty attribuutti alku[H], joka viittaa keon
ensimmäisen binomipuun juureen.
Binomipuut on sijoitettu kekoon H kasvavan asteluvun mukaisessa järjestyksessä:
B0, B1, B2, …, Blog2n
19X.1 Binomipuut
• Seuraavassa vielä pieni esimerkki binomikeosta:
/
/
/
6
2
alku[H]
/
vanhempi[x]
•
•
•
•
14
20
1
0
•
avain[x]
•
•
/
•
•
•
/
•
•
•
•
•
•
•
•
•
15
aste[x]
0
/
/
•
lapsi[x]
•
•
sisarus[x]
/
/
/
/
/
/
/
/
/
19X.2 Binomikeon operaatiot
Binomikeon luonti:
tapahtuu algoritmilla PERUSTA_BINOMIKEKO()
algoritmi on konstruktori, joka varaa muistista tilaa binomikekoa varten
kompleksisuus Θ(1), eli operaatio on vakioaikainen
Pienimmän avaimen etsintä:
Tarkastellaan seuraavassa algoritmia BINOMIKEON_MINIMI(H), joka palauttaa viittauksen
(ensimmäiseen) sellaiseen binomikeon H solmuun, josta löytyy keon pienin avain.
Minimiavain löytyy väkisin jonkin kekoon kuuluvan binomipuun juuresta.
BINOMIKEON_MINIMI(H)
1 y := NIL
2 x := alku[H]
3 min := ∞ /* Asetetaan minimille alkuarvoksi ”ääretön” eli jokin maksimin taatusti ylittävä luku */
4 WHILE x ≠ NIL DO
5
IF avain[x] < min
6
THEN min := avain[x]
7
y := x
8
x := sisarus[x]
9 RETURN y
• Algoritmin kompleksisuus on Ο(log2n), sillä binomipuiden juurilista on käytävä läpi kokonaan.
19X.2 Binomikeon operaatiot
Kahden binomikeon yhdistäminen:
Apumetodilla LINKITÄ_BINOMIPUUT(y, z) pystytään linkittämään kaksi Bk – 1-puuta y ja z
siten, että muodostuu yksi Bk-puu, jonka juureksi päätyy z.
z
sisarus[y] (entinen lapsi[z])
y
Bk – 1
Bk – 1
LINKITÄ_BINOMIPUUT(y, z)
1 vanhempi[y] := z
2 sisarus[y] := lapsi[z]
3 lapsi[z] := y
4 aste[z] := aste[z] + 1
• Kahden binomipuun yhdistäminen on vakioaikainen operaatio (Ο(1)), sillä siihen kuuluu pelkkiä
yksinkertaisia asetuslauseita.
19X.2 Binomikeon operaatiot
Kahden binomikeon limitys:
Apumetodilla BINOMIKEKOJEN_LIMITYS(H1, H2) saadaan limitettyä binomikekojen H1 ja H2
yhdeksi ketjutetuksi juurilistaksi, jossa binomipuiden asteet ovat ei-vähenevässä
järjestyksessä.
Algoritmin toiminta on samanlaista kuin limityslajittelussa käytettävän limitysalgoritmin.
Kannattaa huomioida, ettei operaation tulokseksi yleisesti saada vielä binomikekoa.
• Esimerkki:
alku[H1]
10
6
1
8
12
11
17
14
29
35
25
alku[H2]
18
3
2
20
29
41
30
19X.2 Binomikeon operaatiot
Limityksen tulos:
alku[H]
10
18
1
2
12
20
3
29
41
6
8
30
11
17
14
35
25
Tulokseksi saatu H ei selvästikään ole binomikeko, sillä binomipuita B0 ja B1 esiintyy
limityksen lopputuloksessa kahdesti.
Limitystä tarvitaan kuitenkin välivaiheena avuksi kahden binomikeon unionin
muodostamisessa.
Kahden binomikeon unionin muodostaminen:
• Algoritmi BINOMIKEKOJEN_UNIONI yhdistää binomikeot H1 ja H2 yhdeksi binomikeoksi.
29
19X.2 Binomikeon operaatiot
Unionin muodostamisen vaiheet:
1. Limitetään binomikekojen H1 ja H2 juurilistat kasvavaan järjestykseen käyttämällä algoritmia
BINOMIKEKOJEN_LIMITYS(H1, H2).
Limityksen tuloksena saadussa listassa on nyt samanasteisia binomipuita korkeintaan kaksi
peräkkäin (kts. edellinen esimerkki).
Limitysvaiheen kompleksisuus on Ο(m), missä m tarkoittaa binomikekojen H1 ja H2 juurien
yhteenlaskettua lukumäärää.
2. Käydään limityksen tuloksen juurilista läpi aloittamalla pieniasteisimmasta puusta ja mikäli
löydetään kaksi perättäistä samanasteista Bk – 1-puuta, ne linkitetään yhdeksi Bk-puuksi.
Juurilistaa käsittelevässä algoritmissa osoittaa muuttuja
x tarkasteltavaan juurisolmuun
edell-x juureen, joka edeltää x:ää juurilistassa. Siten sisarus[edell-x] = x.
seur-x juureen, joka seuraa x:ää juurilistassa. Siten sisarus[x] = seur-x.
• Kannattaa huomioida, että jos juurilistassa on kaksi samanasteista solmua, ne sijaitsevat
välttämättä peräkkäin kohdassa 1 tehdyn limityksen ansiosta.
• Juurilistan käsittelyyn liittyy neljä erillistä tapausta, jotka käydään läpi seuraavassa.
19X.2 Binomikeon operaatiot
Tapaus 1: aste[x] ≠ aste[seur-x]
Tällöin x on Bk-puun juuri jollekin k < log2n.
Vastaavasti seur-x osoittaa jonkin Bl-puun juureen siten, että l > k.
Toiminta: ei ole tarpeen linkittää puita toisiinsa, joten siirretään kaikkia kolmea
osoitinmuuttujaa edell-x, x ja seur-x yhdellä eteenpäin.
Seuraavassa hahmotelma tilanteesta:
… edell-x
x
…
seur-x
Bl
Bk
edell-x
x
Bk
seur-x
Bl
…
19X.2 Binomikeon operaatiot
Tapaus 2: aste[x] = aste[seur-x] = aste[sisarus[seur-x]]
Tällöin puussa on kolme samanasteista binomipuuta peräkkäin (miten tämä voi olla
mahdollista?).
Näistä puista x osoittaa ensimmäiseen.
Toiminta: ei tehdä mitään linkityksiä, vaan kaikkia kolmea osoitinmuuttujaa edell-x, x ja
seur-x yhdellä eteenpäin.
Seuraavassa hahmotelma tilanteesta:
… edell-x
x
…
seur-x
Bk
edell-x
Bk
x
Bk
Bk
…
seur-x
Bk
Bk
19X.2 Binomikeon operaatiot
Tapaukset 3 ja 4: aste[x] = aste[seur-x] ≠ aste[sisarus[seur-x]]
Puussa on nyt tarkalleen kaksi samanasteista binomipuuta peräkkäin.
Näistä puista x osoittaa ensimmäiseen.
Toiminta: samanasteiset binomipuut yhdistetään yhdeksi puuksi
Tapaus 3: avain[x] ≤ avain[seur-x]
Tapaus 4: avain[x] > avain[seur-x]
Seuraavassa vielä hahmotelma tilanteesta:
… edell-x
x
…
seur-x
Bk
Bk
edell-x
x
Bl (l > k)
seur-x
Bk
Bk
Bl (l > k)
…
19X.2 Binomikeon operaatiot
•
Seuraavaksi esitetään algoritmi, joka muodostaa kahden binomikeon unionin:
BINOMIKEKOJEN_UNIONI(H1, H2)
1 H := PERUSTA_BINOMIKEKO()
2 alku[H] := BINOMIKEKOJEN_LIMITYS(H1, H2)
3 vapauta keko-objekteille H1 ja H2 dynaamisesti varattu muistitila
4 IF alku[H] = NIL
5 THEN RETURN H
6 edell-x := NIL
7 x := alku[x]
8 seur-x := sisarus[x]
9 WHILE seur-x ≠ NIL DO
10 IF (aste[x] ≠ aste[seur-x]) OR ((sisarus[seur-x] ≠ NIL) AND (aste[sisarus[seur-x]] = aste[x]))
11
THEN edell-x := x
12
x := seur-x
13
ELSE IF avain[x] ≤ avain[seur[x]]
14
THEN sisarus[x] := sisarus[seur-x]
15
LINKITÄ_BINOMIPUUT(seur-x, x)
16
ELSE IF edell-x = NIL
17
THEN alku[H] := seur-x
18
ELSE sisarus[edell-x] := seur-x
19
LINKITÄ_BINOMIPUUT(x, seur-x)
20
x := seur-x
21
seur-x := sisarus[x]
22 RETURN H
19X.2 Binomikeon operaatiot
Algoritmin analyysi:
• Merkitään n1:llä ja n2:lla kekojen H1 ja H2 alkioiden määrää.
• n = n1 + n2 on alkioiden yhteismäärä.
• Keossa H1 on juuria enintään log2n1 + 1.
• Keossa H2 on juuria enintään log2n2 + 1.
• Täten keko H sisältää proseduurin BINOMIKEKOJEN_LIMITYS suorituksen jälkeen juurisolmuja
enintään
log2n1 + log2n2 + 2 ≤ 2 log2n + 2 ≤ 3 log2n (viimeinen epäyhtälö tosi, kun n ≥ 4) = Ο(log2n).
• Jokainen algoritmin BINOMIKEKOJEN_UNIONI while-silmukan suoritus (rivit 9 – 21) vie
ainoastaan vakioajanΟ(1), ja rivit 1 sekä 3 – 8 ovat samoin vakioajassa suoritettavia. Rivin 2
suoritusaika riippuu limityksen tuottaman juurilistan alkioiden lukumäärästä, ja se on edellisen
tarkastelun perusteella logaritminen. Siten algoritmin kokonaissuoritusaika on Ο(log2n).
• Seuraavaksi esitetään vielä esimerkki, miten kahden binomikeon unionin muodostaminen
jatkuu eteenpäin limitysvaiheesta, joka esiteltiin kalvoissa 123 – 124.
19X.2 Binomikeon operaatiot
Tilanne limitysvaiheen päätyttyä:
alku[H]
10
18
1
2
12
20
3
29
6
8
30
17
11
41
25
1) Ensimmäinen korjausvaihe: Kaksi B0-puuta yhdistetään yhdeksi B1:ksi.
juurilistaan tulee nyt kolme perättäistä B1-puuta!
10
1
2
18
12
20
3
29
41
6
8
30
11
25
17
14
35
29
14
35
29
19X.2 Binomikeon operaatiot
2) Toinen korjausvaihe: Toinen ja kolmas B1-puu yhdistetään yhdeksi B2:ksi (ensimmäinen puu
jää paikoilleen lopulliseen kekoon).
koska 1 < 2, linkitetään viimeinen B1-puu keskimmäisen B1-puun lapseksi.
juurilistaan tulee nyt kaksi B2-puuta!
18
3
1
10
2
12
20
29
6
8
30
11
41
17
14
29
35
25
3) Kolmas korjausvaihe: B2-puut yhdistetään yhdeksi B3:ksi.
koska 1 < 3, linkitetään jälkimmäinen B2-puu ensimmäisen B1-puun lapseksi.
juurilistaan tulee nyt kaksi B3-puuta!
1
10
18
29
20
3
2
12
20
6
8
12
11
25
17
14
35
29
19X.2 Binomikeon operaatiot
4) Neljäs korjausvaihe: B3-puut yhdistetään yhdeksi B4:ksi.
koska 1 < 6, linkitetään viimeinen B3-puu ensimmäisen B3-puun lapseksi.
muodostuneen B4-puun sisaruksesta tulee NIL binomikekojen unioni on valmis.
10
1
18
6
11
8
14
17
35
29
29
3
2
12
20
12
20
25
Binäärilukujen yhteenlasku:
• Edellisessä esimerkissä yhdistettiin kaksi binomikekoa, joiden suuruudet ovat 11 ja 7 alkiota.
• Luvun 1110 binääriesitys on 1011
• Luvun 710 binääriesitys on puolestaan 0111
19X.2 Binomikeon operaatiot
Esimerkki: Lasketaan yhteen lukujen 11 ja 7 4-bittiset binääriesitykset.
1
_+ 0
=1 0
B4 B3
•
•
•
0 1 1
1 1 1
0 1 0
B2 B1 B0
(1110)
(710)
(1810)
Muodostettaessa 11- ja 7-kokoisten binomikekojen unioni saatiin tulokseksi 18-solmuinen
binomikeko.
Binääriluku 10010 vastaa lukua 1810, joka oli unionioperaatiossa syntyneen binomikeon koko.
Kyseinen binääriluku vastaa binomipuita B1 ja B4.
Solmun lisääminen binomikekoon:
• Seuraavaksi esiteltävä algoritmi lisää solmualkion x binomikekoon H.
LISÄÄ_BINOMIKEKOON(H, x)
1 H’ := PERUSTA_BINOMIKEKO()
2 vanhempi[x] := NIL
3 lapsi[x] := NIL
4 sisarus[x] := NIL
5 aste[x] := 0
6 alku[H’] = x
7 H := BINOMIKEKOJEN_UNIONI(H, H’)
•
•
•
Algoritmin suorituksen aikana perustetaan uusi binomikeko, jossa on vain solmu x.
Tämän jälkeen yhdistetään binomikeot H ja H’.
Algoritmin kompleksisuus on Ο(1) + Ο(log2n) = Ο(log2n).
19X.2 Binomikeon operaatiot
Minimiavaimen poistaminen:
• Seuraava algoritmi poistaa minimiavaimen binomikeosta H.
POISTA_BINOMIKEON_MINIMI(H)
1 Etsi sellainen keon H juurisolmu x, jolla on pienin avainarvo ja poista x keon H juurilistasta.
2 H’ := PERUSTA_BINOMIKEKO()
3 Käännä x:n lapsisolmujen järjestys sisaruslistassa, aseta lasten isäksi NIL sekä aseta alku[H’]
osoittamaan tämän listan alkuun.
4 H := BINOMIKEKOJEN_UNIONI(H, H’)
5 RETURN x
• Algoritmin kompleksisuus: Ο(log2n)
• Seuraavassa esitetään vielä numeerinen esimerkki minimiavaimen poistamisesta. Oletetaan
lähtötilanteeksi seuraavanlainen binomikeko H:
alku[H]
10
3
6
12
29
30
41
11
25
1
8
17
14
35
29
19X.2 Binomikeon operaatiot
Minimiavain löytyy puun B3 juuresta. Poistetaan kyseinen puu keosta H ja merkitään sen
juurta tunnuksella x.
Saadaan:
alku[H]
10
x
3
6
12
29
11
41
Irrotetaan solmu x keosta H, käännetään sen lapsilista
ja viedään lapsisolmut kekoon H’:
alku[H]
8
30
14
1
29
35
17
25
alku[H’]
10
3
6
12
29
41
30
29
8
14
35
11
25
17
19X.2 Binomikeon operaatiot
Suoritetaan minimikekojen H ja H’ välinen limitys … :
alku[H]
10
29
6
14
12
35
3
8
30
29
11
41
25
… ja lopuksi muodostetaan näiden unioni:
alku[H]
10
29
3
6
14
35
12
11
25
8
29
17
41
30
17
19X.2 Binomikeon operaatiot
Avainarvon pienentäminen:
•
•
•
•
•
Oletetaan, että solmu x kuuluu binomikekoon H.
Solmun x avainarvo halutaan pienentää arvoon k.
Syntyy virhetilanne, jos k > avain[x].
Lisäksi oletetaan, että on käytettävissä suora osoitin binomikeon solmualkioon x.
Toimintaperiaate on samanlainen kuin tavallisessa minimikeossa.
PIENENNÄ_BINOMIKEON_AVAIMEN_ARVOA(H, x, k)
1 IF k > avain[x]
2
THEN virheilmoitus ”uusi avain on nykyistä suurempi: ei kelpaa”
3 avain[x] := k
4 y := x
5 z := vanhempi[y]
6 WHILE z ≠ NIL AND avain[y] < avain[z] DO
7
vaihda avain[y]  avain[z]
8
vaihda myös mahdollinen lisädata solmujen y ja z välillä päittäin
9
y := z
10
z := vanhempi[y]
• Avainarvoa pienentävän algoritmin kompleksisuus: Ο(log2n), sillä minkä tahansa binomipuun
maksimikorkeus keossa on log2n.
19X.2 Binomikeon operaatiot
Alkion poistaminen:
• Oletetaan jälleen, että on käytettävissä suora osoitin binomikeon solmualkioon x.
POISTA_BINOMIKEOSTA(H, x)
1 PIENENNÄ_BINOMIKEON_AVAIMEN_ARVOA(H, x, -∞)
2 POISTA_BINOMIKEON_MINIMI(H)
• Poiston kompleksisuus: Ο(log2n), sillä kummankin rivin (1 ja 2) suorituskustannus on Ο(log2n).
16. Tasoitettu kustannus
•
•
•
Edellä suoritetut algoritmien analyysit ovat perustuneet määräämällä kokonaiskustannus yksittäisten
operaatioiden kustannusten summana.
Tasoitetun kustannuksen analyysissä tarkastellaan yksittäisten operaatioiden sijasta
operaatiojonojen suorituskustannuksia.
Suoritetaan jono perättäisiä operaatioita.
Ajatus: Vaikkakin algoritmin jotkin yksittäiset operaatiot voivat sinällään olla työläitä, niin tästä
huolimatta keskimääräinen työmäärä yhtä operaatiota kohti saattaa jäädä vähäiseksi.
On nimittäin mahdollista, ettei kalliiksi käyvää operaatiota ei ole teknisesti mahdollista
suorittaa kuin vain harvoin!
16. Tasoitettu kustannus
• Tarkastellaan seuraavassa lyhyesti kolmea eri lähestymistapaa tasoitetun kustannuksen
määräämiseksi:
1) Kokonaistyömäärän laskeminen (artikkelissa Aho, Hopcroft, Ullman)
2) Talletusmenetelmä (artikkelissa M. R. Brown, R. E. Tarjan, S. Huddleston ja K. Mehlhorn)
3) Potentiaalimenetelmä (artikkelissa D. D. Sleator)
• Käytetään asiaan tutustumiseksi kolmea esimerkkiongelmaa
1) Pino, jossa monen alkion poisto-operaatio
2) Lukujen binääriesitykseen perustuva laskuri
3) Alkioiden tallentamista dynaamiseen taulukkoon
16.1 Kokonaistyömäärän laskeminen
16.1.1 Pino, jossa monen alkion poisto-operaatio
•
Käytettävissä olevat operaatiot
1) LISÄÄ_PINOON(S, x): lisää alkion x pinon S päällimmäiseksi
kompleksisuus Ο(1) ⇒ jos suoritetaan n kertaa peräkkäin, kustannus Ο(n) (vertaa
silmukkarakenne, jossa vakioaikaista lausetta (lausejonoa)
suoritetaan n kierrosta peräkkäin).
16.1 Kokonaistyömäärän laskeminen
16.1.1 Pino, jossa monen alkion poisto-operaatio
2) OTA_PINOSTA(S): poistaa pinon S päällimmäisen alkion
kompleksisuus Ο(1) ⇒ jos suoritetaan n kertaa peräkkäin, kustannus Ο(n)
3) OTA_PINOSTA_USEITA(S, k): poistaa pinosta S k päällimmäisintä alkiota (tai kaikki
saatavilla olevat alkiot, ellei pinossa ole tarpeeksi alkioita)
1 WHILE NOT tyhjä(S) AND k ≠ 0 DO
2
OTA_PINOSTA(S)
3
k := k – 1
Suoritusaika:
– lineaarinen suhteessa poistettavien alkioiden lukumäärään
– while-silmukkaa suoritetaan min(s, k) kertaa, missä s on pinon S alkioiden
lukumäärä (merkitään |S|)
Suoritetaan nyt operaatioita LISÄÄ_PINOON, OTA_PINOSTA ja OTA_PINOSTA_USEITA peräkkäin
yhteensä n kappaletta jossain järjestyksessä.
• Operaation OTA_PINOSTA_USEITA suoritusaika on pahimmillaan O(n).
• Operaatioita suoritetaan yhteensä n kappaletta.
• Siten operaatiojonon pahimman tapauksen kustannus vaikuttaisi yksinkertaisen analyysin
perusteella olevan n ⋅ (Ο(n)) = Ο(n2) – oletetaan siis tehtävän pelkkiä usean alkion poistooperaatioita yhteensä n kertaa peräkkäin. Ajatuksena on siis varautua aina pahimpaan … .
• … MUTTA: ihan näin huonosti ei kuitenkaan voi käydä! Analysoidaan asiaa syvällisemmin.
16.1 Kokonaistyömäärän laskeminen
16.1.1 Pino, jossa monen alkion poisto-operaatio
• Jokainen pinon S alkioista tuodaan ensinnä jonoon ja poistetaan myöhemmin.
olematonta alkiota ei pystytä poistamaan
• Toisin sanoen, jotta pinosta voitaisiin ottaa pois yhteensä n alkiota (joko yksi kerrallaan tai
useampia samanaikaisesti), ne on selvästikin täytynyt viedä pinoon sitä ennen.
n alkion poistoa on täytynyt edeltää n kappaletta lisäysoperaatioita.
• Kokonaistyömäärä on siis todellisuudessa Ο(n) pahimmassa tapauksessa (toisin kuin arvioitiin
yksinkertaisessa analyysissä).
• Keskimääräinen työmäärä yhtä operaatiota kohti on siis Ο(1).
16.1.2 Binäärilaskuri
• Binäärilaskuri on luvun binääriesitykseen perustuva laskuri, joka laskee ykkösen välein nollasta
eteenpäin.
•
•
•
•
! " ⋅2"
Laskurin arvo on tietyllä hetkellä ∑
Edellä k tarkoittaa luvun bittiesityksen A pituutta.
Laskuri alustetaan nollalla, joten aluksi A = <000…00>.
Esitetään seuraavaksi binäärilaskurin toimintaa kuvaavan algoritmin pseudokoodi. Algoritmi
kasvattaa laskurin arvoa ykkösellä nykyisestä arvostaan.
16.1 Kokonaistyömäärän laskeminen
16.1.2 Binäärilaskuri
KASVATA_BINÄÄRILASKURIA(A, k)
1 i := 0
2 WHILE i < k AND A[i] = 1 DO
3
A[i] := 0
4
i := i + 1
5 IF i < k
6 THEN A[i] := 1
Esimerkki: Oletetaan, että luvun bittiesityksen pituus k = 3
Laskurin arvo
Bittiesitys
Kokonaiskustannus
0
000
0
1
001
1
2
010
3
3
011
4
4
100
7
5
101
8
6
110
10
7
111
11
16.1 Kokonaistyömäärän laskeminen
16.1.2 Binäärilaskuri
•
•
•
•
Binäärilaskurin kasvatusoperaation kustannus on pahimmassa tapauksessa Θ(k) bittien vaihtojen
lukumäärissä mitattuna.
Mikäli laskurin arvon annetaan kasvaa n kertaa peräkkäin, olisi yksinkertaisen analyysin mukaan
kyseisen operaatiojonon kustannus pahimmassa tapauksessa Θ(nk).
taustaoletus: joka kerta vaihdetaan kaikki k bittiä päinvastaisiksi.
Tarkemmin ajatellen on kuitenkin ilmeistä, että
ainoastaan 1. bitti joudutaan vaihtamaan jokaisella operaatiolla
2. bitti vaihdetaan vain joka toinen kerta
3. bitti vaihdetaan joka neljäs kerta
jos bittejä olisi neljä, niistä ylin vaihtuisi joka kahdeksas kerta, ja …
… yleisesti: i. bitti joudutaan vaihtamaan joka 2i – 1. kerta.
Siten n perättäisen binäärilaskurin kasvatusoperaation kokonaiskustannus on:
T(n) = n + n/2 + n/22 + n/23 + … + n/2k – 1 ≤ n(1/20 + 1/21 + …. + 1/2k – 1)
( )
= n ⋅ ∑
=n
•
%
%
( )
≤ 2n(1 – (1/2)k) ≤ 2n
Siten T(n) = Ο(n), joten yhtä operaatiota kohti laskettu kustannus (s. o. tasoitettu kustannus) on
suuruusluokkaa Ο(1).
16.2 Talletusmenetelmä
• Perustavana ajatuksena talletusmenetelmässä on, että operaatioista maksetaan eri
suuruisia maksuja.
Joistakin operaatioista maksetaan todellista kustannusta enemmän.
Toista operaatioista taas maksetaan vähemmän kuin sen todellinen kustannus.
Kuoletetulla kustannuksella tarkoitetaan maksettua yhteissummaa.
Käytettäessä talletusmenetelmää on luonnollisempaa puhua kuoletetusta (eli siis jo
maksetusta) kustannuksesta kuin tasoitetusta.
• Mikäli kuoletettu kustannus on isompi kuin todellinen kustannus, talletetaan näiden erotus
joihinkin tiettyihin objekteihin talletukseksi.
• Talletusta voidaan käyttää maksettaessa sellaisia operaatioita, joiden kuoletettu kustannus
on pienempi kuin todellinen kustannus.
• Kuoletetut kustannukset pitää määritellä huolellisesti:
Talletus ei saa koskaan olla miinuksella (eli ei saada jäädä ”velkaa” missään vaiheessa)
Kuoletettu kustannus pitää saada todellisen kustannuksen ylärajaksi.
• Merkitään, että
ci on i. operaation todellinen kustannus
ĉi on i. operaation kuoletettu kustannus
• Vaatimus: ∑ ĉi ≥ ∑ ci (tehdyistä operaatioista pitää maksaa vähintään käypä hinta)
• Talletus: ∑ ĉi – ∑ ci ≥ 0 (talletuksella tarkoitetaan käytettävissä olevaa ”tilin saldoa”)
16.2 Talletusmenetelmä
16.2.1 Pino, jossa monen alkion poisto-operaatio
• Todellinen kustannus:
Lisäys: 1
Poisto: 1
Usean alkion poisto: min(s, k), missä s on pinon koko tarkasteluhetkellä (eli |S|)
• Näiden todellisten kustannusten valossa voidaan sopia seuraavista tasoitetuista
kustannuksista:
Lisäys: 2
Poisto: 0
Usean alkion poisto: 0
• Ajatuksena siis on, että jokaisesta poisto-operaatiosta maksetaan ennakkomaksu. Täten
jokaisen lisäysoperaation kustannukseksi kirjataan sen todellinen kustannus tuplana.
• Tämän jälkeen poistosta tulee kirjanpidollisesti ”ilmaista lystiä” – riippumatta siitä,
otetaanko jonosta kerrallaan yksi alkio vai useita
maksu poisto-operaatioista on jo maksettu etukäteen.
16.2 Talletusmenetelmä
16.2.1 Pino, jossa monen alkion poisto-operaatio
• Vertauskuvallinen esimerkki ”reaalimaailmasta”: lautaspinon käsittely:
Kun uusi lautanen asetetaan pinoon, maksetaan yhden euron suuruinen maksu pinoon
asettamisesta ja lisäksi toinen euro myöhemmin tehtävää poistoa varten (ensimmäinen
euro rahastetaan heti, mutta toinen jää lautaselle ”lepäämään”).
Kun lautanen aikanaan poistetaan pinosta, maksetaan poisto lautaselle varastoon
jääneellä euron kolikolla.
Selvästikin talletus on aina ei-negatiivinen: jokaisella pinossa olevalla lautasella on oltava
euron kolikko, ja talletus on nolla tarkalleen silloin, kun lautaspino on tyhjä.
Kuoletettu kustannus on todellisen kustannuksen yläraja.
Kuoletettu kustannus on lautasesimerkissä Ο(n). Jos n operaation aikana lautaspino ei
tyhjene, on talletus positiivinen (ollaan maksettu enemmän kuin todellisten
kustannusten verran).
16.2.2 Binäärilaskuri
• Sovitaan seuraavat tasoitetut kustannukset:
Bitin vaihto 0 1 maksaa 2 euroa.
Tästä 1 euro on vaihdon todellinen kustannus.
Toinen euro maksetaan etukäteen siitä, että bitti joskus myöhemmin tullaan
nollaamaan.
Talletusten määrää osoittaa nyt laskurin ykkösten lukumäärä, joka on aina
ei-negatiivinen.
16.2 Talletusmenetelmä
16.2.2 Binäärilaskuri
• Laskurin kasvatusoperaation kuoletettu kustannus määräytyy seuraavasti:
While-silmukan osuus on maksettu etukäteen
Tämän jälkeen enintään yksi bitti vaihdetaan ykköseksi.
Kuoletettu kustannus on enintään 2 euroa.
Kuoletettu kustannus n operaation jonolle on Ο(n).
16.3 Potentiaalimenetelmä
Potentiaalimenetelmä muistuttaa talletusmenetelmää, mutta nyt talletus tulkitaan
tietorakenteeseen varastoiduksi potentiaaliksi.
•
•
•
•
Tallennusmenetelmässä talletus kohdistuu aina johonkin objektiin (lautanen, bitti jne.).
Potentiaalimenetelmässä itse tietorakenne varastoi itseensä potentiaalia.
Potentiaalia voidaan käyttää tuleviin operaatioihin.
Se on operaatiojonojen kustannuksen arvioimismenetelmistä joustavin.
16.3 Potentiaalimenetelmä
Merkitään:
• Di = tietorakenteen tila i. operaation jälkeen
• D0 = tietorakenne lähtötilanteessa
• ci = i. operaation todellinen kustannus
• ĉi = i. operaation tasoitettu kustannus
Potentiaalifunktio: Φ: Di R
• Φ(Di) = tietorakenteen Di potentiaali
• ĉi = ci + Φ(Di) – Φ(Di – 1) = ci + ∆Φ(Di)
Tasoitetun kustannuksen kokonaismäärä
∑ ĉi = ∑(ci + Φ(Di) – Φ(Di – 1))
= ∑ ci + Φ(Dn) – Φ(D0))
• Jos vaaditaan, että Φ(Dn) – Φ(D0) ≥ 0, niin voidaan olla varmoja, että tasoitetun kustannuksen
kokonaismäärä on todellisen kustannuksen yläraja.
• Yleensä on järkevintä määritellä Φ(D0) = 0 ja vaatia, että Φ(Di) ≥ 0 kaikilla i ≥ 1, niin liikutaan
”turvallisilla vesillä”.
• ∆Φ(Di) kuvaa potentiaalin muutosta tietorakenteessa i operaation kohdalla.
16.3 Potentiaalimenetelmä
16.3.1 Pino, jossa monen alkion poisto-operaatio
• Tyhjä pino D0: Φ(D0) = 0.
• Potentiaalifunktio Φ: edustaa pinon alkioiden lukumäärää
• Siten selvästikin Φ(Di) ≥ Φ(D0) kaikilla i ≥ 0.
Lisäysoperaatio:
• Φ(Di) – Φ(Di – 1) = 1
• ĉi = ci + ∆Φ(Di) = 1 + 1 = 2
Usean alkion poisto-operaatio: määritellään x = min(|S|, k)
• Φ(Di) – Φ(Di – 1) = -x
• ĉi = ci + ∆Φ(Di) = x – x = 0
Samoin yhden alkion poisto-operaatiolle ĉi = 0, sillä se voidaan mieltää edellisen
erikoistapaukseksi, kun parametrin k arvo on 1.
• Äskeisen perusteella n operaation tasoitettu kustannus on Ο(n).
• Koska Φ(Di) ≥ Φ(D0) = 0 kaikilla i ≥ 0, niin tasoitettu kustannus on yläraja todellisen
kustannuksen yläraja.
16.3 Potentiaalimenetelmä
16.3.2 Binäärilaskuri
•
•
•
•
•
•
•
Φ = bi, joka tarkoittaa ykkösbittien lukumäärää laskurin i. kasvatusoperaation jälkeen.
Oletetaan, että i. operaatiossa nollataan xi bittiä.
Todellinen kustannus ci ≤ xi + 1.
Jos bi = 0, niin i. operaatio nollasi kaikki k bittiä. Tällöin välttämättä bi – 1 = xi = k.
Jos bi > 0, niin i. operaatio nollaa xi bittiä. Täten bi = bi – 1 – xi + 1.
Kumpi tapaus näistä sitten toteutuukin, on voimassa bi ≤ bi – 1 – xi + 1.
Nyt
∆Φ(Di) = bi – bi – 1 ≤ (bi – 1 – xi + 1) – bi – 1
= 1 – xi.
• Tasoitettu kustannus ĉi = ci + ∆Φ(Di) ≤ (xi + 1) + (1 – xi) = 2.
• Koska Φ(D0) = 0, niin tasoitetun kustannuksen kokonaismäärä on yläraja todelliselle
kustannukselle.
• Siten n operaation tasoitettu kustannus on Ο(n).
16.4 Dynaamiset taulukot
• Taulukko on olio, jolla on ominaisuutena rajattu koko. Kun taulukko on kerran perustettu, sen
kokoa ei enää pysty muuttamaan, sillä se määritellään konstruktorissa.
• Usein voi taulukon käytön ongelmaksi koitua se, ettei ennalta pystytä aavistamaan, paljonko
taulukkoon tullaan alkioita sijoittamaan, eli ei ole tietoa siitä, minkä kokoinen taulukko olisi
järkevää valita.
• Sekä Javassa että C++:ssa dynaaminen taulukko määritellään Vector-luokassa. Ohjelmoijan ei
tarvitse itse huolehtia taulukon kasvattamisesta.
• Esimerkiksi Javan Vector-luokka varaa oletusarvoisesti tilaa vain 10 alkiolle. Kun
tietorakenteeseen lisätään alkioita, luokka kasvattaa taulukon kapasiteettia automaattisesti
kaksinkertaiseksi sopivaksi katsomallaan hetkellä ja kopioi alkiot alkuperäisestä taulukosta
uuteen taulukkoon.
• Tarkasteltavassa toteutuksessa toimitaan siten, että kun varattu taulukko täyttyy, varataan
uusi – kaksi kertaa nykyisen kokoinen – taulukko, kopioidaan alkiot nykyisestä, pienemmästä
taulukosta sinne ja jatketaan normaalisti.
• Tarkastellaan seuraavaksi algoritmia, joka lisää solmualkion x dynaamiseen taulukkoon T.
16.4 Dynaamiset taulukot
LISÄÄ_TAULUKKOON(T, x)
1 IF koko[T] = 0
2 THEN luo uusi 1-alkioinen taulukko T
3
koko[T] := 1
4 IF lkm[T] = koko[T] /* Onko taulukko T täynnä? */
5 THEN Luo taulukko nimeltä uusi, joka on kooltaan 2 ⋅ koko[T]
6
kopio taulukon T alkiot taulukkoon uusi
7
vapauta taulukon T käytössä oleva muistialue
8
T := uusi
9 koko[T] := 2 ⋅ koko[T]
10 Lisää x taulukkoon T
11 lkm[T] := lkm[T] + 1
6.4.1 Kokonaistyömäärän laskeminen
• ci = 1, jos taulukko ei ole täynnä
• ci = (i – 1) + 1 = i, jos taulukko on täynnä
Huom! Taulukko on täynnä, jos ja vain jos i = 2k jollakin kokonaisluvulla k.
16.4 Dynaamiset taulukot
6.4.1 Kokonaistyömäärän laskeminen
Kokonaistyömääräksi saadaan:
 ∑ &" ≤ n + ∑
2
= n + 2log2n + 1 – 1
≤ n + 2 ⋅ 2log2n = 3n
•
Tasoitettu kustannus yhtä operaatiota kohti on siten 3.
6.4.2 Talletusmenetelmä
Jokainen algoritmin LISÄÄ_TAULUKKOON kutsumiskerta maksaa 3 euroa:
• 1 euro tarvitaan uuden alkion tallettamiseen
• Toinen euro maksetaan etumaksua mahdollisesti myöhemmin tehtävästä alkion siirrosta
• Lisäksi kolmas euro maksetaan jonkin toisen – taulukkoon aikaisemmin tuodun – alkion siirrosta
Toimintaperiaate
• Oletetaan, että taulukon koko on juuri äsken kaksinkertaistettu. Taulukon koko on tällöin m + m.
• Oletetaan lisäksi, ettei meillä ole yhtään säästöjä käytettävissä.
• Seuraavan kerran taulukon koko joudutaan tuplaamaan, kun siinä on m + m = 2m alkiota.
• Näiden alkioiden tallettamisen kuoletettu kustannus on 3m euroa.
16.4 Dynaamiset taulukot
• Alkioiden tallettamisen todellinen kustannus on m euroa.
• Alkioiden uuteen taulukkoon siirtämisen todellinen kustannus on 2m euroa.
• Uusia alkioita taulukkoon lisättäessä kertyneet säästöt menetetään, mutta tehtävä onnistui!
6.4.3 Potentiaalimenetelmä
Potentiaalifunktio Φ(T) = 2 ⋅ lkm[T] – koko[T]
• Aluksi lkm[T] = koko[T] = 0, joten Φ(T) = 0.
• Heti taulukon laajennuksen tapahduttua koko[T] = 2 ⋅ lkm[T], joten Φ(T) = 0.
• Juuri ennen laajennusta koko[T] = lkm[T], joten Φ(T) = lkm[T].
Koska lkm[T] ≥ ½ ⋅ koko[T], niin Φ(T) ≥ 0.
Määritellään:
• lkmi = alkioiden määrä i. operaation jälkeen
• kokoi = taulukon koko i. operaation jälkeen
• Φi = taulukon potentiaali i. operaation jälkeen
16.4 Dynaamiset taulukot
Jos taulukkoa ei laajenneta, niin:
• lkmi = lkmi – 1 + 1
• kokoi = kokoi – 1
• ci = 1
Tästä seuraa, että
ĉi = ci + Φi – Φi – 1
= 1 + (2 ⋅ lkmi – kokoi) – (2 ⋅ lkmi – 1 – kokoi – 1)
= 1 + (2 ⋅ lkmi – kokoi) – (2 ⋅ (lkmi – 1) – kokoi)
=1+2=3
Jos taulukkoa laajennetaan, niin
• kokoi = 2 ⋅ kokoi – 1
• kokoi – 1 = lkmi – 1 = lkmi – 1
• ci = lkmi – 1 + 1 = lkmi
Tästä seuraa, että
ĉi = ci + Φi – Φi – 1
= lkmi + (2 ⋅ lkmi – kokoi) – (2 ⋅ lkmi – 1 – kokoi – 1)
= lkmi + (2 ⋅ lkmi – 2(lkmi – 1)) – (2 ⋅ (lkmi – 1 – 1) – (lkmi – 1) )
= lkmi + 2 – lkmi + 1 = 3
19 Fibonacci-keot
Fibonacci-keot on esitelty ensi kertaa artikkelissa: Michael L. Fredman & Robert E. Tarjan: Fibonacci
heaps and their uses in improved network optimization algorithms, Journal of the ACM 34,(1987),
596 – 615
Operaatio
Keko
Binomikeko
Fibonacci-keko
Θ(1)
Θ(1)
Θ(1)
Θ(log2n)
Ο(log2n)
Θ(1)
Θ(1)
Ο(log2n)
Θ(1)
Θ(log2n)
Θ(log2n)
Ο(log2n)*
Θ(n)
Ο(log2n)
Θ(1)
PIENENNÄ_AVAINARVOA**
Θ(log2n)
Θ(log2n)
Θ(1)*
POISTA_SOLMU**
Θ(log2n)
Θ(log2n)
Ο(log2n)*
PERUSTA_KEKO
LISÄÄ
MINIMI
POISTA_MINIMI
UNIONI
*) = tasoitettu kustannus
**) = oltava käytettävissä osoitin tarkasteltavaan alkioon (alkiota ei jouduta erikseen etsimään)
19 Fibonacci-keot
• Fibonacci-keko on kekorakenne, joka on tasoitetun kustannuksen suhteen tehokkaampi kuin
tavallinen keko ja binomikeko.
• Fibonacci-kekoa käyttämällä voidaan toteuttaa prioriteettijono, jonka vahvuuksina ovat
vakioaikainen (Θ(1)) lisäys, pienimmän solmun löytäminen, avainarvon (prioriteetin)
pienentäminen ja unioni,
• Solmun ja pienimmän avaimen poistaminen voidaan suorittaa ajassa Ο(log2n).
• Fibonacci-keon operaatioiden toimintafilosofia: pyritään olemaan laiskoja. Ei tehdä mitään,
ennen kuin on pakko
kun töitä lopulta joudutaan tekemään, tehdään kerralla paljon!
19.1 Fibonacci-keon rakenne
• Jokaisessa Fibonacci-keon solmussa on neljä viittausta muihin solmuihin: vanhempaan,
edeltävään sisarukseen, seuraavaan sisarukseen ja johonkin lapseen.
• Sisaruslista on toteutettu kahteen suuntaan linkitettynä rengaslistana.
• Fibonacci-keon jokainen puu on minimikekojärjestyksessä.
• Tietoa keon pienimmästä alkiosta säilytetään erikseen attribuutissa min[H].
• On mahdollista, että samanasteisia puita on keossa useampia kuin yksi (toisin kuin
binomikeoilla).
• Juurilistan ei tarvitse olla asteluvun mukaan ei-vähenevässä järjestyksessä.
19.1 Fibonacci-keon rakenne
• Seuraavassa yksi hahmotelma Fibonacci-keon rakenteesta:
min[H]
19.1 Fibonacci-keon rakenne
Esitysmuodoista
Edellä kuvattuun esitystapaan perustuen seuraavat perusoperaatiot ovat vakioaikaisia:
• Juurilistaan lisääminen ja poisto (lisätään esimerkiksi minimiarvon sisältävän solmun viereen)
• Kahden juurilistan limittäminen
• Kahden binomipuun linkittäminen toisiinsa
• Jonkun solmun lapsilistan yhdistäminen juurilistaan (lapsien isäosoittimia NIL-arvoiksi päivittämättä)
Tämä selittyy sillä, että mainitut operaatiot päivittävät vain vakiomäärän sisaruslistan viittauksia, sekä
linkitys päivittää näiden lisäksi vielä yhden vanhempi-osoittimen.
Minimin haku, lisäys ja unioni
•
•
•
Minimin hakeminen on helppoa, sillä meillä on käytettävissä suora min[H]-osoitin pienimmän
avaimen sisältävään solmuun.
Myös uuden alkion lisääminen on helppoa, sillä uusi solmualkio x vain lisätään juurilistaan, ja
tarvittaessa päivitetään min[H]-viittaus ajan tasalle.
Jos puolestaan yhdistetään kaksi Fibonacci-kekoa toisiinsa unionioperaatiolla, niin yksinkertaisesti
vain limitetään niiden juurilistat yhteen ja päivitetään min[H]-viittaus kuntoon.
Edellä esitetyt operaatiot ovat vakioaikaisia (Θ(1)).
19.2 Minimialkion poisto
Minimiavaimen poisto algoritmilla POISTA_MINIMI on jossain määrin monimutkaisempaa.
1. Aluksi minimialkio poistetaan juurilistasta, ja sen lapsilista yhdistetään juurilistaan. Ellei
huomioida vielä tässä vaiheessa lapsien isälinkkien asettamista arvoon NIL, tämä saadaan
tehtyä ajassa Θ(1).
2. Tämän jälkeen käytetään puhdistusalgoritmia, joka päivittää poistetun solmun lapsilistasta
juureen nousseiden solmujen vanhempi-viittaukset sekä linkittää pareittain saman kokoiset
binomipuut, kunnes on jäljellä yksistään eri asteisia binomipuita. Puhdistusalgoritmin
pseudokoodi esitellään seuraavassa:
PUHDISTA(H)
1 uusiminimi := jokin juurilistaan kuuluva solmu
2 FOR i := 0, 1, …, log2n DO
3
B[i] := NIL /* B on puhdistuksessa käytettävä aputaulukko. */
4 FOR jokaiselle juurilistan solmulle v DO
5
vanhempi[v] := NIL (∗)
6
IF avain[uusiminimi] > avain[v]
7
THEN uusiminimi := v
8
YHDISTÄ_SAMANASTEISET(v)
19.2 Minimialkion poisto
YHDISTÄ_SAMANASTEISET(v)
1 w := B[aste[v]]
2 WHILE w ≠ NIL DO
3
B[aste[v]] := NIL
4
IF avain[v] ≥ avain[w]
5
THEN vaihda v  w
6
Poista w juurilistasta (∗∗)
7
LINKITÄ(w, v)
8
w := B[aste[v]]
9 B[aste[v]] := v
Seuraavassa on nähtävissä hahmotelma Fibonacci-keon puhdistamisen etenemisestä:
0
1
2
3
B
v
19.2 Minimialkion poisto
0
1
2
3
B
v
0
B
1
2
3
v
19.2 Minimialkion poisto
Huomioita edellisiin kahteen algoritmiin:
• Kannattaa huomioida, että algoritmi YHDISTÄ_SAMANASTEISET linkittää alkiot siten, että
minimikeko-ominaisuus säilyy (kahden samaa astetta olevan binomipuun avainarvoja verrataan
keskenään, ja näistä pienempi jää juurilistaan).
• Algoritmin PUHDISTA kompleksisuus on Ο(r+), missä r+ on Fibonacci-keon juurilistan pituus ennen
kyseisen algoritmin suorittamista.
• Tämä voidaan todeta tarkastelemalla sitä, kuinka monta kertaa tähdellä merkityt rivit suoritetaan:
Rivi (∗) suoritetaan yhden kerran kullekin juurilistan v solmulle.
Rivi (∗∗) suoritetaan enintään yhden kerran kutakin juurilistan solmua w kohti (osoitin w
kulkee v:n jäljessä).
• Koska algoritmi POISTA_MINIMI tekee vain vakiomäärän työtä ennen puhdistusalgoritmin
kutsumista, niin sen kokonaissuoritusaika on
Ο(r+) = Ο(r + aste[min[H]],
•
•
•
missä r on juurilistan pituus ennen POISTA_MINIMI-algoritmin suorituksen aloittamista.
Vaikka aste[min[H]] on luokkaa Ο(log2n), on silti mahdollista, että r = Θ(n) – tarkastellaan vaikkapa
tapausta, jossa yhtään alkiota ei ole vielä ehditty poistaa.
Täten algoritmin POISTA_MINIMI suoritusaika on luokkaa O(n).
Algoritmin POISTA_MINIMI suorittamisen jälkeen juurilistan pituus on Ο(log2n), sillä kaikilla puilla
on tuolloin eri aste, ja korkein aste on enintään log2n.
19.2 Minimialkion poisto
Tasoitettu kustannus
• Jokainen alkion lisäys Fibonacci-kekoon kasvattaa lukua r, joka on juurilistan pituus ennen alkion
poistoa.
• Lisätään jokaiseen lisäykseen kiinteän suuruinen ”puhdistusmaksu” ja käytetään näin säästyneitä
maksuja puhdistusalgoritmin kustannuksiin.
• Tämän vuoksi POISTA_MINIMI-algoritmin osalta maksamatta on vain Ο(aste[min[H]]) = Ο(log2n).
• Se, että Ο(aste[min[H]]) = Ο(log2n), todistetaan myöhemmin.
Tarkastellaan asiaa seuraavassa formaalisemmin potentiaalin avulla.
Algoritmin tasoitettu kustannus ĉ on todellisen kustannuksen c ja potentiaalin muutoksen ∆Φ summa.
Määritellään Fibonacci-keon potentiaaliksi Φ juurisolmujen lukumäärä.
Olkoon r juurisolmujen määrä ennen POISTA_MINIMI-algoritmin suoritusta ja r’ algoritmin suorituksen
jälkeen. Tällöin
• ∆Φ = r’ – r
• c = r + aste[min[H]]
• Tasoitettu kustannus on edellisten summa, eli ĉ = c + ∆Φ = r’ + aste[min[H]].
• Koska r’ = Ο(log2n) ja kunkin solmun aste on Ο(log2n), siten algoritmin POISTA_MINIMI tasoitettu
kustannus on Ο(log2n).
19.3 Arvon pienentäminen
Tässä tarkastellaan, miten solmualkion avainarvoa voidaan pienentää. Suoritusaika on
pahimmassa tapauksessa Ο(log2n), mutta tasoitettu kustannus on ainoastaan Ο(1).
Algoritmissa, joka pienentää solmun v avainarvoa, on vain kaksi yksinkertaista sääntöä:
1. Korota v juurilistaan (tässä tulee samalla koko v-juurinen alipuu mukana).
2. Kun jonkin solmun w kaksi lasta on korotettu juurilistaan, korota myös w välittömästi.
Jotta jälkimmäistä sääntöä voitaisiin soveltaa tehokkaasti, jatkossa joitain Fibonacci-keon solmuja
ns. merkitään.
Solmu on merkitty, jos tarkalleen yksi sen lapsista on korotettu juurilistaan.
Kun merkitty solmu korotetaan juurilistaan, sen ”merkki” poistetaan.
PIENENNÄ_AVAINARVOA(v, k)
1 avain[v] := k
2 IF k < avain[min[H]]
THEN min[H] := v
3 KOROTA(v)
19.3 Arvon pienentäminen
Seuraavaksi esiteltävä algoritmi KOROTA on rekursiivinen. Jos korotetun solmun vanhempi on
merkitty, sekin korotetaan.
KOROTA(v)
1 kumoa solmun v merkintä
2 IF vanhempi[v] ≠ NIL
3
THEN Poista v isäsolmunsa lapsilistasta
4
Lisää v juurilistaan
5
IF vanhempi[v] on merkitty
6
THEN KOROTA(vanhempi[v])
7
ELSE merkitse vanhempi[v]
Katsotaan seuraavaksi esimerkkiä Fibonacci-keon alkion avainarvon pienentämisestä. Aluksi
pienennetään solmun f avainarvoa. Yhtään solmua ei ole alun perin merkittynä.
a
b
l
p
f
g
m
n
h
i
o
c
d
j
k
e
19.3 Arvon pienentäminen
f
l
a
b
m
p
g
h
i
n
c
d
j
k
e
o
Koska f:n avainarvoa pienennettiin, se nostettiin alipuineen juurilistaan. Samalla solmu b
merkittiin, sillä sen lapsilistassa esiintynyt f korotettiin. Oletetaan, että seuraavaksi pienennetään
solmun d avainarvoa. Solmu d ei esiinny samalla haku polulla kuin ainoa merkitty solmu b.
f
l
p
b
m
g
n
h
c
i
a
d
e
k
j
o
Nyt myös d on nostettu juurilistaan. Samasta syystä kuin edellä merkittiin solmu b, nyt merkitään
myös solmu a. Sovitaan, että nyt vuorostaan pienennetään solmun j avainarvoa. Solmulla j ei ole
lapsia, joten se nousee juurilistaan yksinään.
19.3 Arvon pienentäminen
a
f
l
b
m
p
g
c
h
j
e
d
k
i
n
o
Nyt myös j on nostettu juurilistaan. Tällä kertaa merkittiin puolestaan solmu c, joka on juureen
nostetun j:n isäsolmu. Pienennetään lopuksi vielä solmun h avainarvoa, ja katsotaan mitä nyt tapahtuu.
l
p
f
b
m
g
n
h
a
c
e
j
d
k
i
o
Koska juurilistaan viimeksi korotetun h:n isäsolmu b oli merkitty – eli b:n jokin lapsista (f) – on jo
aikaisemmin nostettu juurilistaan, joudutaan sinne nostamaan myös b alipuineen. Samalla b:n merkintä
kumotaan. Merkintä poistuu kuitenkin myös a:lta, sillä a on viimeksi juurilistaan korotetun b:n merkitty
isäsolmu. Rekursio päättyy tähän, sillä a on jo ennestään juurilistassa (sillä ei enää ole isäsolmua).
19.3 Arvon pienentäminen
Tasoitettu kustannus
Solmun avainarvon pienentämisen suoritusaika on
Ο(1 + peräkkäisten merkittyjen v:n esivanhempien määrä)
Binomipuilla korkeus on luokkaa Ο(log2n), joten jos avainarvon pienentämisen eri vaiheissa käsiteltäisiin
vain täydellisiä binomipuita, suoritusaika olisi selvästikin Ο(log2n).
Valitettavasti korottaminen tuhoaa tämän ominaisuuden!
Seuraavassa suoritetaan tasoitetun kustannuksen analyysi. Siinä sovitaan, että potentiaali on
merkittyjen solmujen lukumäärä.
Kun tehdään vähän työtä, merkittyjen solmujen määrä kasvaa korkeintaan yhdellä – kun
tehdään paljon työtä, merkittyjen solmujenkin määrä vähenee paljon.
Olkoot m ja m’ merkittyjen solmujen määrä ennen ja jälkeen avainarvon pienennysoperaatiota.
Todellinen kustannus on
c = 1 + perättäisten merkittyjen v:n esivanhempien määrä, ja potentiaalin muutos on
m’ – m ≤ 1 – peräkkäisten merkittyjen v:n esivanhempien määrä
Koska ĉ = c + ∆Φ ≤ 2, niin algoritmin PIENENNÄ_AVAINARVOA tasoitettu kustannus on Ο(1).
19.4 Asteen yläraja
Merkitään koko[v]:llä v-juurisen alipuun solmujen määrää (v mukaan lukien).
Lemma: Kaikille Fibonacci-keon solmuille v on voimassa koko[v] ≥ Faste[v] + 2.
Todistus: Luetellaan solmun v lapset siinä järjestyksessä, jossa ne on linkitetty solmuun v.
Tarkastellaan tilannetta juuri ennen kuin i:nneksi vanhin lapsi wi linkitettiin
v:hen. Tällöin v:llä oli vähintään i – 1 lasta. Koska puhdistusalgoritmi linkittää
ainoastaan keskenään samanasteisia solmuja, on linkityksen alkaessa
aste[wi] = aste[v] ≥ i – 1
Tämän jälkeen ainoastaan yksi wi:n lapsi on voitu korottaa juurilistaan –
muutoinhan wi olisi korotettu sinne itsekin. Täten
•
•
•
•
aste[wi] ≥ i – 2
Olkoon sk pienin mahdollinen solmujen lukumäärä puussa, jonka juuren aste on k.
Selvästikin s0 = 1, s1 = 2 ja s2 = 3.
Edellä olevan perusteella i:nneksi vanhimman lapsen wi aste on vähintään i – 2, ja täten sen koko on
vähintään si – 2 (sk:n määritelmän perusteella).
Voidaan kirjoittaa nyt seuraava yhtälö (oletetaan, että s-1 = 1)
sk ≥ ∑ '" − 2
19.4 Asteen yläraja
Havaitaan seuraavanlainen yhteys Fibonaccin lukuihin:
F0 = 0, F1 = 1, = s-1, F2 = 1 = s0, F3 = 2 = s1, F4 = 3 = s2
Lisäksi voitaisiin osoittaa induktiolla, että
sk ≥ 1 + ∑ )" = Fk + 2
Induktiolla voitaisiin niin ikään osoittaa, että Fk + 2 ≥ φk, missä
φ=
≈ 1.618
on kultaisen leikkauksen luku.
Yhdistämällä tulokset saadaan
koko[v] ≥ Faste[v] + 2 ≥ φaste[v], josta edelleen saadaan
aste[v] ≤ logφkoko[v] = Ο(log2n).
19.5 Lopullinen analyysi
Kannattaa huomioida, että edellä POISTA_MINIMI ja PIENENNÄ_AVAINARVOA käyttävät erilaisia
potentiaalifunktioita. Mikäli emme pysty löytämään yhtä potentiaalifunktiota, joka toimii molemmilla
operaatioilla, emme voi taata luvattuja tasoitettuja kustannuksia.
Arvataan, että sopiva potentiaalifunktio voisi olla
Φ = r + 2m
Tarkastellaan seuraavaksi huolellisesti kutakin keko-operaatiota ja sen vaikutusta sekä juurten että
merkittyjen solmujen määrään. Kuten edellä, r ja m ovat juurisolmujen ja merkittyjen solmujen
lukumäärät ennen kutakin operaatiota, ja r’ ja m’ ovat vastaavat lukumäärät operaation jälkeen.
Operaatio
Todellinen c
∆r
∆m
∆Φ
Tasoitettu ĉ
LISÄYS
1
1
0
1
2
UNIONI
1
0
0
0
1
POISTA_MINIMI
r + aste(min)
r’ – r
0
r’ – r
r’ + aste(min)
PIENENNÄ_AVAINARVOA
1 + m – m’
1 + m – m’
m – m’
1 + m’ – m
2
Huomioi erityisesti, että yhden solmun korottaminen algoritmissa PIENENNÄ_AVAINARVOA vaatii
vakioajan ja se kasvattaa juurten lukumäärää yhdellä; lisäksi enintään yksi merkitsemätön solmu
korotetaan.
Koska r’ + aste[[min[H]] = O(log2n), niin kaikki on kunnossa.
22 Tiivistelmä graafialgoritmeista
• Seuraavassa oletetaan, että graafi G koostuu pisteiden ja niitä yhdistävien kaarten joukosta.
Merkitään, että G = (V, E).
• Graafi voi olla suunnattu tai suuntaamaton.
• Suunnattu graafi G on järjestetty pari (V, E), missä V on äärellinen joukko ja E koostuu
järjestetyistä pareista (u, v). Joukkoa V kutsutaan pisteiden (kärkien, solmujen) joukoksi, ja E on
puolestaan viivojen (kaarten) joukko.
• Suuntaamattoman graafin G = (V, E) viivajoukko E koostuu suuntaamattomista pareista {u, v},
missä u ≠ v. Usein myös merkintää (u, v) käytetään (aaltosulkeiden tilalle kaarisulkeet).
• Suunnatussa graafissa u on viivan (u, v) lähtöpiste ja v on kyseisen viivan päätepiste. Sen
pisteen aste tarkoittaa pisteestä lähtevien, ja sisäaste pisteeseen saapuvien kaarten määrää.
• Suuntaamattomassa graafissa molemmat pisteet, joita kaari yhdistää, ovat päätepisteitä, ja
tällöin niiden sanotaan olevan vierekkäisiä.
• Suunnatussa graafissa myös silmukat eli pisteestä u itseensä johtavat viivat ovat laillisia.
• Graafin G = (V, E) vierekkäisyyslista on |V|:stä listasta koostuva taulukko Vlistat.
• Kaikilla graafin pisteillä v ∈ V, Vlistat[v] koostuu sellaisista pisteistä u ∈ V siten, että (v, u) ∈ E.
• Yleensä alkioiden järjestyksellä vierekkäisyysmatriisissa ei ole merkitystä.
• Mikäli graafi on suuntaamaton, niin kaaren (u, v) esiintyminen takaa myös kaaren (v, u)
esiintymisen samaisessa graafissa. Tästä ei kuitenkaan ole takeita suunnatussa graafissa.
22 Tiivistelmä graafialgoritmeista
• Esimerkki suuntaamattomasta graafista: ote Suomen rautatieverkosta
Seinäjoki
Kuopio
Vaasa
Parkano
Jyväskylä
Haapamäki
Joensuu
Jämsä
Pieksämäki
Pori
Tampere
Orivesi
Mikkeli
Kokemäki
Toijala
Hämeenlinna
Rauma
Loimaa
Riihimäki
Turku
Lahti
Kouvola
Kerava
Salo
Karjaa
Hanko
Lappeenranta
Helsinki
22 Tiivistelmä graafialgoritmeista
• Ohessa esimerkki suunnatusta graafista:
G
2
1
3
4
5
• Graafin vierekkäisyyslistat näyttäisivät puolestaan seuraavilta:
1
2
2
3
3
1
4
5
5
2
3
2
4
22.1 Leveyshaku
•
•
•
•
•
Leveyshaku on yksi yksinkertaisimmista graafien hakualgoritmeista.
Syöte: Suunnattu tai suuntaamaton graafi G = (V, E) ja lähtöpiste s ∈ V.
Tuloste: Algoritmi laskee jokaiselle pisteelle v ∈ V lyhimmän etäisyyden etäisyys[v] lähtöpisteeseen s.
Lisäksi lasketaan arvo π[v] = u, missä u on pisteen v edeltäjä lyhimmällä polulla s v.
π-arvoja käytetään leveyshakupuun konstruoimiseen.
Algoritmin idea: Pisteestä s lähetetään ”aalto” kaikkiin mahdollisiin etenemissuuntiin.
Aalto osuu ensiksi lähtöpisteestä yhden etäisyydellä oleviin pisteisiin.
Seuraavaksi osutaan kahden etäisyydellä oleviin pisteisiin jne.
Jokaisella graafin pisteellä v ∈ V on attribuutit:
etäisyys[v] osoittaa etäisyyden lähtöpisteestä
π[v] = pisteen v edeltäjä lyhimmällä polulla s v
Kannattaa huomioida, että jos graafin jotkin pisteet eivät ole saavutettavissa lähtöpisteestä
s, niitä ei koskaan sieltä aloitettaessa löydetä.
Aputietorakenteena käytetään jonoa Q.
Voidaan osoittaa, että jono Q koostuu suorituksen aikana sellaisista pisteistä, joiden
etäisyysarvot ovat
i, i, i, …, i, i + 1, i + 1, …, i + 1
22.1 Leveyshaku
• Seuraavassa on esitettynä leveyshakualgoritmin pseudokoodi …
LEVEYSHAKU(G, s)
1 FOR jokaiselle solmulle u ∈ V[G] – {s} DO
2
etäisyys[u] := ∝
π[u] := NIL
3
4 etäisyys[s] := 0
5 π[s] := NIL
6 Q := ∅ /* Alustetaan jono Q tyhjäksi. */
7 LISÄÄ_JONOON(Q, s)
8 WHILE Q ≠ ∅ DO
9
u := OTA_JONOSTA(Q)
10
FOR jokaiselle pisteelle v ∈ Vlistat[u] DO
11
IF etäisyys[v] = ∝ /* Pistettä v ei ole vielä tarkasteltu? */
12
THEN etäisyys[v] := etäisyys[u] + 1
13
π[v] := u
14
LISÄÄ_JONOON(Q, v)
• … ja seuraavalla sivulla esitetään esimerkki algoritmin toiminnasta yhdelle esimerkkigraafille:
22.1 Leveyshaku
r
s
t
u
r
s
t
u
r
s
t
u
∝
0
∝
∝
1
0
∝
∝
1
0
2
∝
∝
∝
∝
∝
∝
1
∝
∝
∝
1
2
∝
v
w
x
y
v
w
x
y
v
w
x
y
w r
s Q: 1 1 t
s
0 s
t
u
r
1
0
2
∝
1
0
2
1
2
∝
2
1
v
w
x
y
v
w
r Q:
t x v
Q: 2 2 2
r
s
u
r
1
0
2
3
1
2
1
2
3
2
w
x
y
v
v
Q:
u y
3 3
s
u
r
2
3
1
0
2
3
2
∝
2
1
2
3
y
v
w
x
x v u
2 2 3
Q:
t
r t x
s Q: 1 2 2 t
t
0
1
w
Q:
y
3
Q:
2
u
3
r
1
s
0
u
x
y
v u y
2 3 3
t
2
u
3
2
3
2
1
2
3
x
y
v
w
x
y
Q: ∅
22.1 Leveyshaku
Leveyshaun analyysi
•
•
•
Jokainen piste alustetaan riveillä 2 ja 3. Tämän vaiheen kompleksisuus on Ο(V) (kyseistä merkintää
käytetään pidemmän ja oikeaoppisemmanΟ(|V|) asemesta).
Lisäksi jokainen graafin piste laitetaan jonoon ja poistetaan jonosta enintään kerran. Yhden jonooperaation kompleksisuus on Ο(1). Näin ollen yhteenlaskettu jono-operaatioiden kompleksisuus on
Ο(V).
Suunnatuissa graafeissa vierekkäisyyslistojen yhteispituus on |E|ja suuntaamattomissa graafeissa se
on 2|E|. Täten riviltä 8 käynnistyvän while-silmukan yhteiskompleksisuus on Ο(E).
Koko algoritmin kompleksisuus on Ο(E + V).
Leveyshakupuut
Määritellään leveyshakupuu graafina Gπ = (Vπ, Eπ), missä
Vπ = {v ∈ V | π[v] ≠ NIL} ∪ {s}.
Eπ = {(π[v], v) | v ∈ Vπ – {s}}.
Täten Vπ koostuu kaikista sellaisista pisteistä, jotka ovat saavutettavissa pisteestä s käsin (mukaan lukien
piste s itse).
Kulkemalla puussa Gπ pisteestä v pisteeseen s π-arvoja pitkin kuljetaan itse asiassa lyhin polku pisteestä
s pisteeseen v käänteisessä järjestyksessä.
22.1 Leveyshaku
• Seuraavassa esitetään vielä äskeisen esimerkin leveyshakupuu:
π
s
π
π
r
w
π
v
π
t
π
u
π
x
π
v
• Kannattaa huomioida, että leveyshaku löytää aina parhaan mahdollisen ratkaisun, mutta se
toimii hitaasti etsittäessä kaukana lähtöpisteestä olevia solmuja graafin ollessa laaja.
22.2 Syvyyshaku
• Syvyyshaku on esitelty ensimmäistä kertaa artikkelissa Edward F. Moore: The shortest path
through a maze, Proceedings of the International Symposium on the Theory of Switching
(Harward University Press 1959), sivut 285 – 292.
• Algoritmin perusajatus: haetaan aina vain syvemmältä tietyn strategian ohjaamana:
peräännytään vasta sitten kun on pakko.
• Jokaisella solmulla v ∈ V on seuraavat attribuutit:
π[v]: solmun v edeltäjä (kuten leveyshaussa)
väri[v]: solmun väri (valkoinen, musta, harmaa)
löydetty[u]: aikaleima, jolloin solmu on ensi kertaa löydetty
valmis[u]: aikaleima, jolloin solmun käsittely on saatu päätökseen
• Lisäksi on käytössä globaali muuttuja aika, jota käytetään solmujen aikaleimojen asettamiseen.
• Aikaleimat ovat väliltä 1, 2, …, 2|V|, sillä jokainen solmu löydetään ja saadaan käsiteltyä
valmiiksi tarkalleen kerran. Täten pitää paikkansa
1 ≤ löydetty[v] ≤ valmis[v] ≤ 2|V|
• Seuraavaksi esitetään syvyyshakualgoritmin sekä sen tarvitseman apumetodin pseudokoodit.
22.2 Syvyyshaku
SYVYYSHAKU(G)
1 FOR jokaiselle solmulle u ∈ V[G] DO
2
väri[u] := valkoinen
3
π[u] := NIL
4 aika := 0
5 FOR jokaiselle pisteelle u ∈ V[G] DO
6
IF väri[u] = valkoinen /* Pisteessä u ei ole vielä käyty */
7
THEN KÄSITTELE_SOLMU(u)
KÄSITTELE_SOLMU(u)
1 väri[u] := harmaa /* Harmaa väri merkitsee solmun ottamista käsittelyyn. */
2 aika := aika + 1
3 löydetty[u] := aika
4 FOR jokaiselle solmulle v ∈ Vlistat[u] DO
5
IF väri[v] = valkoinen
6
THEN π[v] := u
7
KÄSITTELE_SOLMU(v)
8 väri[u] := musta /* Solmun u käsittely päättyy. */
9 aika := aika + 1
10 valmis[u] := aika
22.2 Syvyyshaku
• Tarkastellaan seuraavaksi syvyyshaun etenemistä seuraavassa suunnatussa graafissa.
Oletetaan, että taustalla on etenemisstrategia, jonka mukaan pyritään siirtymään aina
aakkosissa mahdollisimman alussa olevalla kirjaimella nimettyyn solmuun.
a
e
1 | 12
g
13 | 16
8 | 11
b
f
9 | 10
2|7
c
3|4
d
5|6
h
14 | 15
22.2 Syvyyshaku
Syvyyshaun analyysi
•
•
•
Syvyyshakualgoritmin suoritusaika: Rivien 1 – 3 ja 5 – 7 silmukat vievät ajan Ο(V) pois lukien se aika,
joka kuluu metodin KÄSITTELE_SOLMU suorittamiseen.
Proseduuria KÄSITTELE_SOLMU kutsutaan tarkalleen kerran kullakin solmulla v, sillä sitä kutsutaan
ainoastaan solmun ollessa valkoinen. Heti ensi töikseen se värjää käsittelyyn saamansa solmun
harmaaksi. Suoritettaessa kutsua KÄSITTELE_SOLMU(v) rivien 4 – 7 silmukkaa suoritetaan
|Vlistat[v]| kertaa.
Selvästikin
∑/∈1 |+,"'- . | = Θ(E)
•
Koko algoritmin suoritusajaksi saadaan siten Θ(E + V).
Syvyyshakupuut
”Syvyyshakupuu” voi muodostua useista erillisistä puista, joten sitä kutsutaan syvyyshakumetsäksi.
•
Syvyyshakumetsän Gπ = (Vπ, Eπ) kaarten joukko on
Eπ = {(π[v], v) | v ∈ V ja π[v] ∉ NIL}
22.2 Syvyyshaku
• Edellinen esimerkki tuottaisi seuraavanlaisen syvyyshakumetsän:
π
a
π
g
π
b
π
c
π
e
h
π
d
f
• Kannattaa huomioida, ettei syvyyshaku löydä välttämättä parasta ratkaisua. Sen sijaan ratkaisu
voi löytyä huomattavasti leveyshakua nopeammin, jos hakustrategia on toimiva (aavistetaan
hyvin, minne päin haku kannattaa suunnata).
22.3 Dijkstran algoritmi
• Painotetulla graafilla tarkoitetaan graafia, jossa jokaiseen kaareen liittyy paino w(e).
• Tämä voidaan tulkita esimerkiksi suuntaamattomassa graafissa kaaren päätepisteiden väliseksi
etäisyydeksi (esimerkiksi välimatkoja kuvaava karttagraafi).
• Dijkstran algoritmi ratkaisee graafin lyhimmän polun ongelman, kun syötteenä on sellainen
painotettu graafi G = (V, E) siten, että w(e) ≥ 0 kaikille e ∈ E, eli jokaisen viivan paino on einegatiivinen.
• Kyseistä algoritmia voidaan soveltaa sekä suuntaamattomille että suunnatuille painotetuille
graafeille.
• Algoritmi on leveyshaun painotettu yleistys. Se laskee lyhimmät polut annetusta pisteestä s
graafin muihin pisteisiin.
• Aputietorakenteena Dijkstran algoritmissa käytetään graafin pisteiden prioriteettijonoa.
• Seuraavaksi esitetään algoritmin sekä sen käyttämien kahden apurutiinin pseudokoodit.
DIJKSTRA(V, E, w, s)
1 ALUSTA_LÄHTÖPISTE(G, s)
2 Q := V[G]
3 WHILE Q ≠ ∅ DO
4
u := POISTA_MINIMI(Q)
5
FOR jokaiselle solmulle v ∈ Vlistat[u] DO
6
TESTAA_ETÄISYYS(u, v, w)
22.3 Dijkstran algoritmi
• Apualgoritmi ALUSTA_LÄHTÖPISTE asettaa tarpeelliset alkuarvot etäisyyksille ja edeltäjille.
ALUSTA_LÄHTÖPISTE(G, s)
1 FOR jokaiselle solmulle v ∈ V[G] DO
2
etäisyys[v] := ∝
3
π[v] := NIL
4 etäisyys[s] := 0
• Apualgoritmi TESTAA_ETÄISYYS tutkii, että löydettiinkö aikaisempaa lyhyempi yhteys pisteiden
u ja v välille.
TESTAA_ETÄISYYS(u, v, w)
1 IF etäisyys[v] > etäisyys[u] + w(u, v)
2
THEN etäisyys[v] := etäisyys[u] + w(u, v)
π[v] := u
3
22.3 Dijkstran algoritmi
• Seuraavassa esitetään pieni esimerkki Dijkstran algoritmin toiminnasta seuraavalle graafille G,
kun lähtöpisteeksi valitaan a.
G
b
8
3
5
6
9
4
1
c
e
f
a
2
7
5
d
a
b
c
d
e
f
Alustus:
0 / NIL
∝ / NIL
∝ / NIL
∝ / NIL
∝ / NIL
∝ / NIL
Valitaan a:
0 / NIL
3/a
9/a
7/a
∝ / NIL
∝ / NIL
Valitaan b:
0 / NIL
3/a
8/b
7/a
9/b
11 / b
22.3 Dijkstran algoritmi
a
b
c
d
e
f
Valitaan d:
0 / NIL
3/a
8/b
7/a
9/b
11 / b
Valitaan c:
0 / NIL
3/a
8/b
7/a
9/b
11 / b
Valitaan e:
0 / NIL
3/a
8/b
7/a
9/b
10 / e
Valitaan f:
0 / NIL
3/a
8/b
7/a
9/b
10 / e
Lyhimmät polut pisteestä a graafin G muihin pisteisiin ovat siten seuraavat:
a b: 3 (suora yhteys ab)
a c: 8 (reitti abc)
a d: 7 (suora yhteys ad)
a e: 9 (reitti abe)
a f: 10 (reitti abef)
22.3 Dijkstran algoritmi
• Tarkastellaan seuraavassa veilä Dijkstran algoritmin kompleksisuutta:
Rivin 1 alustusrutiini vie ajan Ο(V).
Prioriteettijonojen operaatioiden suoritusajat:
LISÄYS-operaatiota suoritetaan rivillä 2. Yksi operaation suoritus vie ajan Ο(log2V),
ja operaatioita suoritetaan |V| kappaletta. Täten lisäysoperaatioiden kokonaisaika
on Ο(V log2V).
Operaatiota POISTA_MINIMI suoritetaan rivillä 4. Yksi operaation suoritus vie ajan
Ο(log2V). Myös näitä operaatioita tehdään |V| kappaletta, joten POISTA_MINIMIoperaatioiden kokonaissuoritusaika on samoin Ο(V log2V).
Avainarvon pienennysoperaatioita suoritetaan rutiinin TESTAA_ETÄISYYS rivillä 8.
Yksi operaation suoritus vie aikaa Ο(log2V). Näitä operaatioita tehdään joko |E| tai
2|E| kappaletta riippuen siitä, onko kyseessä suunnattu vai suuntaamaton graafi.
Täten avainarvon pienentämisoperaatioiden kokonaissuoritusaika on Ο(E log2V).
Siten koko algoritmin suoritusaika on Ο((V + E) log2V).