Träd allmänt Träd allmänt Ett generellt träd är Antingen det tomma trädet, eller en rekursiv struktur: rot /. \ /... \ t1... tn där t1,..., tn i sin tur är träd och kallas subträd, vars rotnoder kallas söner eller döttrar till rot-noden. Rot-noden i sin tur kallas fader eller moder till subträdens rotnoder. Datastrukturer, träd 1
Binära träd Binära träd Ett binärt träd är antingen 1. det tomma trädet, eller 2. så består det av en nod, kallad roten till trädet, som innehåller något värde och två delträd, som kallas vänster respektive höger delträd, som i sin tur är binära träd. För att namnge förhållanden mellan noder brukar man använda son, fader, farfar, farföräldrar, kusiner,... (alt dotter, mor, morföräldrar...) Med ett löv menar man en nod som har två tomma delträd. Med djupet eller höjden av ett träd menas antalet noder i den längsta vägen från roten till ett löv. (Alternativt antalet bågar från roten till lövet). Övriga noder kallas interna noder. Komplexiteten anges normalt med O(f(n)), där n är antalet noder, eller ibland O(f(h)) där h är höjden av trädet. Datastrukturer, träd 2
Binära träd Binära träd Alla träd kan transformeras till ett binärt träd. Algoritmen är: Låt vänstraste sonen vara vänster delträd och låt alla syskon till vänstraste sonen bilda en högerkedja av subträd. t.ex: A A / \ / / \ blir: B B C D / \ / / \ E C E F G / \ F D \ G Datastrukturer, träd 3
Exempel: Uttryck som träd Binära träd Kallas också syntaxträd. * / \ / \ / \ + - / \ \ 2 9 3 Notera att här behövs inga paranteserer eller någon prioritet, varför det är enkelt att exekvera, via rekursion: beräkna( op ) = beräkna( vdt ) op beräkna( hdt ) / \ vdt hdt Datastrukturer, träd 4
Traversering av binära träd Binära träd Två huvudformer: bredden först eller djupet först. Vid djupet först väljes alltid vänster delträd före höger delträd, varför vi får tre varianter av i vilken ordning noderna skall behandlas: preorder: roten, noderna i vänster delträd, noderna i höger delträd inorder: noderna i vänster delträd, roten, noderna i höger delträd postorder: noderna i vänster delträd, noderna i höger delträd, roten Datastrukturer, träd 5
Balansering av träd Binära träd 1. nodbalanserat: Skillnaden i antalet noder mellan vänster och höger delträd är högst 1. 2. höjdbalanserat: Skillnaden i höjd (djup) mellan vänster och höger delträd är högst 1. 3. nivåbalanserat: Alla nivåer är fyllda, utom den nedersta som fylls på från vänster till höger. Notera att höjden av dessa träd är alla av O( 2 log n ), där n är antalet noder i trädet. Datastrukturer, träd 6
Implementering av binära träd Binära träd Den vanligaste konkreta implementeringarna av binära träd är den länkade strukturen. T.ex. binära sökträd, AVL-träd, rödsvarta träd, Splay-träd,... Binära sökträd är obalanserade. AVL-träd är höjdbalanserade. Rödsvarta träd och Splay-träd semihöjdbalanserade. Det finns även implementeringar i fält, t.ex en så kallad heap, vilken är nivåbalanserad. Samtliga dessa träd är dessutom organiserade efter objektens storlek, vanligtvis given av metoden compareto i Java. Datastrukturer, träd 7
Binära sökträd Binära sökträd Ett binärt sökträd är ett binärt träd, där alla värden i det vänstra delträdet är mindre än värdet i roten. Alla värden i det högra delträdet är större än eller lika med värdet i roten. Vänster och höger delträd är i sin tur binära sökträd. Den konkreta implementeringen av ett binärt sökträd är vanligen en länkad struktur, där noderna är en kvadrupel: [ rotvärde, ] pekare till vänster delträd, pekare till höger delträd, pekare till fadernod, Datastrukturer, träd 8
Operationer på binära sökträd Binära sökträd De viktigaste operationerna för ett binärt sökträd är: avgöra om trädet är tomt. lägga till ett element i trädet. ta bort ett element i trädet. söka efter ett element i trädet. Eftersom ett träd är en rekursiv struktur, användes ofta rekursion för att implementera dessa operationer. (visa på tavlan, iterativa varianter är väl beskrivna i boken) Datastrukturer, träd 9
Nackdelar med vanliga binära sökträd Binära sökträd Träden kan bli mycket skeva, vilket innebär att de tre sista operationerna blir i värsta fall av O( n ), där n är antalet noder. Detta är samma som för listor! För att sänka komplexiteten användes normalt balanserade träd, så att komplexiteten för dessa operationer blir av O( 2 log n ) Datastrukturer, träd 10
AVL-träd AVL-träd AVL kommer från Adelson-Velski och Landis, som beskriver hur man kan balansera binära sökträd så att operationerna blir av O( 2 log n ). Balanseringar vid insättning i och uttag ur trädet ser till att trädet alltid är höjdbalanserat. Detta görs med hjälp av höjdinformation i noderna. Själva balanseringen är av O( 1 ). Att avgöra var balanseringen skall ske är däremot av O( 2 log n ). Det finns fyra balanseringar, rotateleft, rotateright, doublerotateleft och doublerotateright. (se läroboken) rotateleft läses ett steg åt vänster (kan vara från i vissa böcker) Datastrukturer, träd 11
Antal noder i ett AVL-träd AVL-träd Till att börja med har vi att minimala antalet noder för ett träd av höjden h är: minn od(0) = 0 minn od(1) = 1 minnod(h) = minnod(h 1) + minnod(h 2) + 1 Denna funktion är exponentiell med avseende på h, vilket lätt inses genom: 2 h 2 minnod(h) 2 h h = 1,2,... Vi kan därför använda oss av att: n O( 2 h ) och h O( 2 log n ), där n är antalet noder och h är höjden i ett AVL-träd. Datastrukturer, träd 12
Minimalt AVL-träd AVL-träd Skapa ett minimalt AVL-träd av höjden 5. (Med minimalt avses så lite noder som möjligt.) minnod(5) blir 12. Vi bildar ett träd av höjden 5, genom att som vänster delträd ta ett minimalt träd av höjden 4 och som höger delträd ta ett minimalt träd av höjden 3. minnod(4) är 7, varför vi bygger trädet: 8 / \ / \ mintree mintree 1..7 9..12 Datastrukturer, träd 13
Minimalt AVL-träd AVL-träd Vi fortsätter på samma sätt med med deltäden, och får till slut 8 / \ / \ 5 11 / \ / \ 3 7 10 12 / \ / / 2 4 6 9 / 1 Uppgift till nästa föreläsning: skriv ett Java-program som ger ett minimalt träd för en godtycklig höjd. Datastrukturer, träd 14
Splay-träd Splay-träd I många sammanhang kan man observera att om man söker en nod, så är det stor sannolikhet att jag kommer att söka efter det snart igen. Därför lyfter vi upp den sökta noden (eller noden ovanför ) till att bli ny rot och passar samtidigt på att balansera trädet på tillbakavägen. Vi har 6 operationer zig, zag, zigzag, zagzig, zigzig och zagzag. (Se det utdelade häftet.) Notera att: zig är samma sak som rotateleft zigzag är samma sak som doublerotateleft zag är samma sak som rotateright zagzig är samma sak som doublerotateright Datastrukturer, träd 15
Röd-svarta träd Röd-svarta träd Ett röd-svart träd är ett binärt sökträd där vi dekorerat varje nod med en färg och för vilket gäller: 1. Varje nod måste vara röd eller svart. 2. Roten är alltid svart. 3. Om en nod är röd, så måste dess barn vara svart(a). 4. Varje väg från roten ner till ett löv måste innehålla samma antal svarta noder. Datastrukturer, träd 16
Binära balanserade sökträd Algoritm för insättning i röd-svarta träd, enligt top-down med flip Som vanligt vid insättning av nytt element i ett binärt sökträd, så startar vi vid roten och söker oss ner i trädet tills vi hittar en ledig plats. Vid insättning i ett röd-svart träd finns en del varianter, men det vanligaste är att följa nedanstående regler: 1. På väg ner användes flipregeln: om en nod har två röda noder byts färgerna för dessa tre noder, dvs: svart röd / \ ==> / \ röd röd svart svart Om nu röds förälder är röd, så justeras trädet enligt regel 2 eller 3 nedan. Datastrukturer, träd 17
Binära balanserade sökträd Algoritm för insättning, fortsättning 2. Om den nedersta röda noden är ett ytterelement görs enkelrotation på den översta röda, dvs om vänster ytter svart G / svart P röd P ==> / \ / röd x röd G röd x samt motsvarande för höger ytter. 3. Om den nedersta röda noden är ett innerelement görs dubblelrotation på den nedersta röda noden, dvs om vänster inner: svart G / svart x röd P ==> / \ \ röd P röd G röd x samt motsvarande för höger inner. Datastrukturer, träd 18
Binära balanserade sökträd Algoritm för insättning, fortsättning 4. När den lediga platsen hittats, så läggs det nya elementet in och färgas röd. Om fadern till den nu inlagda noden också är röd justeras trädet enligt regel 2 och 3 ovan. 5. Slutligen återställs färgen för hela trädets rot till svart om den har råkat ändrats till röd under insättningens gång. Datastrukturer, träd 19