Binära träd Algoritmer och Datastrukturer Markus Saers markus.saers@lingfil.uu.se Upplägg Binära träd (9) Binära sökträd (0.) Träd Många botaniska termer Träd, rot, löv, gren, Trädets rot kan ha ett antal barn Varje barn utgör roten till ett nytt träd Binära träd Rekursiv definition Trädet är Tomt Har två träd som barn Grammatisk definition R Ø R RR Tomma träd brukar inte skrivas ut Binära träd Antal löv på ett träd moder/förälder + A vänster barn höger barn x - B C 3 8 Ø 7 Ø Ø Ø Ø Ø Ø Ø Ø Ø Ø Ø A Ø Ø A löv(ø) = 0 löv(a) = löv(a) = löv(v) + löv(h) V H
Höjden på ett träd En nods nivå V Ø A H höjd(ø) = höjd(a) = + max(höjd(v), höjd(h)) Roten är på nivå 0 Övriga noder är på förälderns nivå + Avlägsnaste lövets nivå = trädets höjd Egenskaper hos binära träd Tvåträd Alla icke tomma noder har två icke tomma barn Fullt Alla icke tomma noder har två lika höga tvåträd som barn Är tvåträd Är kompletta Komplett Trädet är vänsterfullt x+=3 (3 )/ = Representation av kompletta träd Kan representeras med ett fält Från en nod på position i kan vi hitta Modern på position (i )/ (heltalsdivision) Vänster barn på position i+ Höger barn på position i+ x+=4 0 3 4 5 6 (4 )/ =,5 = 0 3 4 5 6 Binary Tree Theorem Binära-träd-teoremet? n + t höjd löv t t Tvåträd och fulla träd: = Fulla träd: = Genomlöpning (Traversal) Noderna i ett träd kan löpas igenom på olika sätt Alla noder behandlas exakt en gång Fyra vanliga sätt att löpa igenom I ordning Post-ordning Pre-ordning Bredden först
I ordning (in order) Post-ordning Algoritmiskt Behandla vänster barn Behandla roten Behandla höger barn vänster-rot-höger x A + Algoritmiskt Behandla vänster barn Behandla höger barn Behandla roten vänster-höger-rot Ger postfix- eller polsknotation x A + A x B + C B C A B C + x B C Pre-ordning Bredden först Algoritmiskt Behandla roten Behandla vänster bar Behandla höger barn rot-vänster-höger Ger prefixnotation x A + Löper igenom trädet nivå för nivå Algoritmiskt Initialisera med roten på kö Medan det finns noder i kön: Ta ut den nod som står på tur och behandla den x Köa det vänstra barnet Köa det högra barnet A + x A + B C B C x A + B C B C Binära sökträd Exempel Introducerar en ordning över noderna Alla noder i vänster barn är mindre än roten Alla noder i höger barn är större än roten Båda barnen är binära sökträd Strikt ordning Inga likvärdiga element (inga dubbletter) < > istället för Heltal som exempel 3
Användbarhet Kontrollera om en nod finns i trädet hitta (contains) Lägga till nod (add) Ta bort nod (remove) Stämmer väl överens med vad man kan göra med en mängd (set) Viktigt att behålla egenskaperna som gör det till ett binärt sökträd Kontrollera om en nod finns i trädet Algoritmiskt: contains(n) Om roten är tom så finns inte n i trädet Om n = roten så finns n i trädet Annars: Om n < roten: kontrollera om n finns i vänster barn Om n > roten: kontrollera om n finns i höger barn contains() contains() > < contains() contains(69) = finns i trädet! 69 > 4
contains(69) contains(69) 69 < 69 > contains(69) contains(69) 69 > tom nod 69 finns inte i trädet! Var ska den nya noden in i trädet? Algoritmiskt add(n) Om n = roten så fanns noden redan i trädet Gör inget, vi tillåter inte dubbletter Om n < roten: lägg noden i vänster barn Om n > roten: lägg noden i höger barn Om vi hamnar i ett tomt träd, ersätt det med ett nytt träd som har n som rot 7 7 < 5
7 7 < 7 7 < 7 7 > 7 Tom nod Ø Ta bort nod Svårt att behålla kraven för att det ska vara ett binärt träd Flera lösningar finns Bokens 7 6
remove() remove() Enkelt eftersom är ett löv Enkelt eftersom är ett löv 0 0 0 0 remove() remove(0) Enkelt eftersom är ett löv Svårare eftersom 0 har ett barn 0 0 0 0 remove(0) remove(0) Svårare eftersom 0 har ett barn Svårare eftersom 0 har ett barn 0 0 0 0 7
remove(0) remove() Svårare eftersom 0 har ett barn Knepigt, eftersom har två barn! Viss variation på hur man utför det här steget Boken remove() remove() s s remove() remove() s 8
remove() Implementation i Java Beskrivs ingående i boken Metoden för att få tag i efterföljande nod enligt den strikta ordningen beskrivs också Undviker konsekvent rekursion Effektivare Svårare att förstå? Prova gärna själva! Effektivitet Hitta Hur snabba är procedurerna i förhållande till antalet noder i trädet? Hitta Lägg till Ta bort Vi behöver ställa frågan har jag hittat rätt, och om inte: vilket barn ska jag fortsätta leta i? Sökträdets struktur garanterar att vi har vårt svar när vi når ett löv Tidskomplexiteten är linjär mot trädets höjd Antalet steg vi behöver ta = trädets höjd Lägg till Liknar hitta, med skillnaden att det vi letar efter är en plats att placera en ny nod Ställ frågan kan jag bo här, och om inte: ska jag bo i vänster eller höger barn? Tidskomplexiteten är linjär mot höjden Ta bort Hitta noden som ska bort (Hitta dess efterföljare) Möblera runt lite Oberoende av trädets storlek Hitta noden + hitta dess efterföljare Två hitta-operationer Tidskomplexiteten är linjär mot dubbla höjden I praktiken närmare linjär mot höjden 9
Slutsats Trädoperationer är beroende av trädets höjd Ta bort och hitta väsentligt mycket snabbare än i listor O(h) vs. O(n) Lägg till är långsammare än i listor O(h) vs. O() Höjden är viktig Lägre höjd = snabbare operationer Fler element = högre höjd Vi vill ha snabba operationer på stora samlingar av element! Kan vi veta något om höjden? Värsta fallet: Värsta fallet: Värsta fallet: Värsta fallet: 3 3 5 0
Värsta fallet: Värsta fallet: Höjden = n I praktiken en länkad lista Kallas kedja 3 5 8 Bästa fallet: fulla träd n = ( x h ) h = log ((n + ) ) h = log n 5 3 8 3 34 89 45 47 44 46 48 Bästa fallet: fulla träd Vi kan göra trädoperationer O(log n) Vad betyder det? n = 00 O(7) n = 000 O(0) n = 0 000 O(4) n = 00 000 O(7) n = 000 000 O(0) n = 000 000 000 O(30) Att hitta nålen i höstacken Givet en samling om en miljard element vill vi hitta ett specifikt element Vi har tur, det är det första vi tittar på! Tidsåtgång, lista: Tidsåtgång, träd: Vi har otur, det är det sista vi tittar på! Tidsåtgång, lista: 000 000 000 Tidsåtgång, träd: 30 Tur är bra men inget vi förlitar oss på! Kan vi garantera fulla träd? Egenskapen full rubbas i regel när man sätter in eller tar bort noder Kan vi garantera typ fulla träd? Balanserade träd! Varje gång vi sätter in eller tar bort en nod möblerar vi om så att trädet är i någorlunda balans