Download de presentatie
De presentatie wordt gedownload. Even geduld aub
GepubliceerdMaurits Sanders Laatst gewijzigd meer dan 10 jaar geleden
1
1 Datastructuren Zoekbomen II Invoegen en weglaten
2
2 Dit onderwerp Binaire Zoekbomen: vorige keer Wat is een binaire zoekboom (eigenschap) Zoeken Minimum Maximum Opvolger / Voorganger Binaire Zoekbomen: nu Een extra query (vb) Invoegen Weglaten Binaire Zoekbomen: hierna Optuigen: snelle “order queries” Balanceren: zorg dat de diepte O(log n) blijft
3
3 Binaire zoekboom Wortel bevat een key (met pointer naar bijbehorend object met extra gegevens …) Linker deelboom bevat alleen kleinere () keys Rechter deelboom bevat alleen grotere () keys Soms sta je toe dat een key vaker voorkomt, soms niet 47 42 23 12 45 31 65 55 49 67 9960
4
4 Binaire zoekboom Je kan ook de NIL’s tekenen 47 42 23 12 31 65 55 49 67 9960
5
5 Zoeken in een binaire boom Iterative-Tree-Search(x,k) while (x != NIL and k != key(x)) do if ( k < key(x)) then x = left(x) else x = right(x) return x; 47 42 23 12 31 65 55 49 67 9960 Kost O(h) tijd als boom hoogte h heeft
6
6 Zoeken van Minimum Tree-Minimum(x) {Zoek het minimum in de boom met wortel x} while (left(x) != NIL) do x = left(x); return x; 47 42 23 12 31 65 55 49 67 9960 Het minimum is altijd de “meest linkse” knoop Tijd: O(h) – h hoogte van de boom Het minimum is altijd de “meest linkse” knoop Tijd: O(h) – h hoogte van de boom
7
7 Zoeken van Maximum Tree-Maximum(x) {Zoek het minimum in de boom met wortel x} while (right(x) != NIL) do x = right(x); return x; 47 42 23 12 31 65 55 49 67 9960 Maximum is meest rechtse knoop Tijd: O(h) met h hoogte van de boom Maximum is meest rechtse knoop Tijd: O(h) met h hoogte van de boom
8
8 Opvolgers en voorgangers I Opvolger van knoop x: 1. Als de rechter- deelboom van x niet leeg is, dan is de opvolger van x het minimum van die rechter-deelboom 2. Als die wel leeg is dan zit die opvolger NIET onder x … Tree-Successor(x) if (right(x) != NIL) then return Tree- Minimum(right(x)) else … x
9
9 Opvolger die niet onder x zit Stel x heeft lege rechter-deelboom Ga omhoog de boom in, zolang je in rechterdeelbomen zit Dus je gaat “links- omhoog” Daarna ga je nog 1 keer een stap omhoog Tree-Successor(x) if (right(x) != NIL) then return Tree- Minimum(right(x)) y = parent(x); while (y != NIL and x == right(y)) do x = y; y = parent(y); return y;
10
10 Tree-successor Tree-Successor(x) if (right(x) != NIL) then return Tree- Minimum(right(x)) y = parent(x); while (y != NIL and x == right(y)) do x = y; y = parent(y); return y; 15 8 7 17 2910 65 55 49 67 9960 40
11
11 Lineair in de hoogte Alle operaties: Search, Minimum, Maximum, Successor, Predecessor kunnen in O(h) met h de hoogte van de boom Er bestaan zoekbomen met hoogte O(lg n), bijvoorbeeld neem een complete binaire boom Later zien we hoe we logaritmische diepte kunnen handhaven
12
12 Veel andere queries Er zijn veel andere vragen die snel beantwoord kunnen worden mbv een binaire zoekboom Voorbeeld: Geef in volgorde alle keys die k zijn voor een gegeven k (k hoeft niet zelf in de boom te zitten)
13
13 Code voor voorbeeld Geef in volgorde alle keys die k zijn voor een gegeven k (k hoeft niet zelf in de boom te zitten) Idee: recursief algoritme: vergelijk k met waarde van wortel en ga dan in recursie in de delen waar dat nodig is … Roep aan: ListKG(root.T, k) ListKG(node x, sleutel k) if (x == NIL) then Doe niets else if key(x) k then ListKG(left(x)); Druk af key(x); ListKG(right(x)) else ListKG(left(x))
14
14 Analyse voorbeeld Correct, want … In goede volgorde want inorder! Let op rol van NIL’s Tijd: O(r + h) als we r antwoorden rapporteren en de boom hoogte h heeft ListKG(node x, sleutel k) if (x == NIL) then Doe niets else if key(x) k then ListKG(left(x)); Druk af key(x); ListKG(right(x)) else ListKG(left(x))
15
15 Invoegen en weglaten Invoegen: Nieuwe knopen kunnen we altijd als blad toevoegen Het algoritme zoekt een goede plek op waar de nieuwe key als blad kan worden toegevoegd Weglaten is wat moeilijker (straks)
16
16 Invoegen Tree-insert voegt een knoop altijd toe in een blad (NIL-knoop) We lopen eerst naar beneden in de boom en zoeken een blad Dat blad zit vlakbij z Tree-Insert(T,z) {z is een knoop met left(z) == right(z) == NIL} y = NIL; x = root(T); while (x != NIL) do y = x; {y is steeds de ouder van x} if (key(z) < key(x)) then x = left(x) else x = right(x) {x is een blad van de boom “vlakbij” key(z)} … en dan …
17
17 15 8 7 17 2910 65 55 49 67 9960 40 15 8 7 17 2910 65 55 49 67 9960 40 12
18
18 Invoegen - II Als we ‘t blad gevonden hebben hangen we z onder y Als y == NIL: de boom was eerst leeg Anders kijk je of je z links of rechts onder y moet hangen Tree-Insert(T,z) y = NIL; x = root(T); while (x != NIL) do y = x; if (key(z) < key(x)) then x = left(x) else x = right(x) parent(z) = y; if (y == NIL) then root(T) = z (T lege boom) else if (key(z) < key(y) then left(y) = z else right(y) = z
19
19 Weglaten Weglaten: als je een blad weglaat: makkelijk Anders: je kan de knoop niet zomaar weglaten, dan krijg je een gat Verplaats een andere knoop naar het ontstane gat: welke? Later: herbalanceren 15 7 17 2910 ?
20
20 Weglaten Bekijk verschillende gevallen: Knoop heeft geen kinderen (makkelijk) Knoop heeft alleen linkerkind Knoop heeft alleen rechterkind (net zo als vorige geval, maar gespiegeld) Knoop heeft zowel linkerkind als rechterkind
21
21 Weglaten: geval 1 1e geval: knoop heeft geen kinderen Dan kan je de knoop gewoon weglaten Ouder van z krijgt een pointer naar NIL erbij Tree-Delete(T,z) {z is een knoop in de boom T} if (left(z)==NIL and right(z) == NIL) then if (parent(z) == NIL) then T = NIL {z was de enige knoop, de boom is nu leeg} elseif (left(parent(z))== z) then left(parent(z)) = NIL else right(parent(z)) = NIL Gooi knoop z weg 15 8 7 17 2910 15 8 7 17 29
22
22 Weglaten – geval 2a Geval 2a: z heeft maar 1 kind, zeg een linkerkind en een ouder Dan hangen we dat kind van z direct onder de ouder van z … if (left(z) != NIL and right(z) == NIL and parent(z) != NIL) then x = left(z); if (z == left(parent(z)) then left(parent(z)) = x parent(x) = parent(z); Gooi z weg else right(parent(z)) = x; parent(x) = parent(z); Gooi z weg 15 8 7 17 29 15 7 17 29 z is niet de wortel
23
23 Geval 2b z heeft alleen een linkerkind, geen rechterkind, maar ook geen ouder (is de wortel) Dan laten we z weg, en wordt het linkerkind de wortel van T if (left(z) != NIL and right(z) == NIL and parent(z) == NIL) then T = left(z); Gooi z weg 15 8 7 17 29 4215 8 7 17 29 z is de wortel
24
24 Weglaten 3 Als z alleen een rechterkind heeft gaat e.e.a. net zo als geval 2 (2a en 2b), met links en rechts verwisseld if (left(z) == NIL and right(z) != NIL) … 17 29
25
25 Weglaten 4 Laatste geval: z heeft twee kinderen Veel lastiger! Let op: hier verschillen CLRS 2e druk en CLRS 3e druk (en later) Idee: vind de opvolger van z en verplaats die naar de plek van z 15 8 7 37 39 20 8 7 37 39
26
26 Weglaten – een nuttig lemma Lemma. Als z twee kinderen heeft, dan heeft de opvolger y (successor) van z geen linkerkind Bewijsidee. Stel dat x een linkerkind is van y. Dan kan je laten zien dat z < x < y en dus is y niet de opvolger van z, tegenspraak. QED z right(z) y x
27
27 Weglaten: twee subgevallen Laat y de opvolger zijn van x Geval 4-1: y is het rechterkind van x Geval 4-2: y is niet het rechterkind van x 15 8 7 37 39 20 8 7 37 39 x x y y
28
28 Weglaten: geval 4-1 (y rechterkind x) We laten x weg y is het de opvolger van x Stel y is het rechterkind van x We verplaatsen de node van y naar de plek van x Goed zetten: Pointer van ouder van x naar x gaat nu naar y Linkerkind van x wordt linkerkind van y Als x de wortel was, wordt y de wortel 20 8 7 37 39 x y 20 8 7 37 39 y
29
29 Weglaten: geval 4-1 (y rechterkind x) y = successor(x); if (parent(y) == x) then: if (parent(x) == NIL) then: {wortel} Root(T)=y if (parent(x) != NIL and left(parent(x)==x) {x is linkerkind} left(parent(x) = y parent if (parent(x) != NIL and right(parent(x)==x) {x is rechterkind} right(parent(x) = y … 20 8 7 37 39 x y 20 8 7 37 39 y
30
30 Weglaten: geval 4-1 (y rechterkind x) … parent(left(x))= y left(y) = left(x) parent(y) = parent(x) {Rechterkind van y blijft hetzelfde} {Nu kan x weggegooid} 20 8 7 37 39 x y 20 8 7 37 39 y
31
31 Weglaten: geval 4-2 (y niet rechterkind x) y wordt verplaatst naar positie van x Rechterboom van y komt op plek van y 15 8 7 37 20 x y 39 29 15 8 7 37 20 39 29 y
32
32 Stap 1: pointers van en naar de ouder is net als geval 4-1 Oldparenty = parent(y) if (parent(y) == x) then: if (parent(x) == NIL) then: {wortel} Root(T)=y if (parent(x) != NIL and left(parent(x)==x) {x is linkerkind} left(parent(x)) = y parent if (parent(x) != NIL and right(parent(x)==x) {x is rechterkind} right(parent(x)) = y
33
33 Daarna linker en rechterkinderen {links net als 4-1} left(y) = left(x) parent(left(x))= y {rechterkind van y nu goed zetten:} w = right(y) parent(w) = oldparenty left(parent(w))=w right(y) = right(x) parent(right(y))=y 15 8 7 37 20 x y 39 29 15 8 7 37 20 y 39 29
34
34 Opmerking De code in het boek is Compacter Moeilijker te snappen dat het correct werkt Werkt in ongeveer dezelfde tijd
35
35 Tijd Alle operaties: zoeken, invoegen, weglaten, minimum, maximum opvolger, voorganger, kunnen in O(h) tijd, met h de hoogte van de binaire zoekboom Verschillende andere operaties kunnen in O(n) tijd, zie ook werkcollege: Opsommen van knopen in gesorteerde volgorde … Hoe groot kan h zijn?
36
36 Hoe groot kan h zijn? Beste geval: plm. lg n (complete binaire boom) Slechtste geval: n (elke knoop heeft maar 1 kind)
37
37 Gebalanceerde bomen Extra werk bij invoegen en weglaten om te zorgen dat de hoogte van de boom O(log n) blijft Veel verschillende oplossingen hiervoor. Wij bekijken een elegante vorm: de rood-zwart- bomen (red-black trees) en varianten
Verwante presentaties
© 2024 SlidePlayer.nl Inc.
All rights reserved.