AVL-träd | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
engelsk A.V.L träd | ||||||||||||||||
Sorts | sökträd | |||||||||||||||
Uppfinningens år | 1968 | |||||||||||||||
Författare | Adelson-Velsky Georgy Maksimovich och Landis Evgeny Mikhailovich | |||||||||||||||
Komplexitet i O-symboler | ||||||||||||||||
|
||||||||||||||||
Mediafiler på Wikimedia Commons |
Ett AVL-träd är ett höjdbalanserat binärt sökträd : för vart och ett av dess hörn skiljer sig höjden på dess två underträd inte med mer än 1.
AVL är en förkortning som bildas av de första bokstäverna av skaparna (sovjetiska forskare) Adelson-Velsky Georgy Maksimovich och Landis Evgeny Mikhailovich .
Den maximala höjden på ett AVL-träd för ett givet antal noder [1] :
var:
(runda upp)
(avrunda nedåt)
(avrunda nedåt).
Antalet möjliga höjder är mycket begränsat i praktiken (med 32-bitars adressering är den maximala höjden 45, med 48-bitars adressering är det 68), så det är förmodligen bättre att förberäkna alla värden för minimitalet av noder för varje höjd med den rekursiva formeln för Fibonacci-trädet :
,
,
.
Mellanvärden av antalet noder kommer att motsvara den tidigare (lägre) höjden.
Med avseende på ett AVL-träd är vertexbalansering en operation som, om höjdskillnaden mellan det vänstra och högra underträdet = 2, ändrar föräldra-barn-länkarna i underträdet till detta vertex så att skillnaden blir <= 1, annars ändrar ingenting. Det angivna resultatet erhålls genom rotationer av underträdet i den givna vertexen.
4 typer av rotationer används:
1. Liten vänsterrotation Denna rotation används när höjdskillnaden mellan a-delträd och b-delträd är 2 och höjd C <= höjd R.
2. Stor vänsterrotation Denna rotation används när höjdskillnaden mellan a-underträd och b-underträd är 2 och höjden på c-underträdet > höjd R.
3. Liten högerrotation Denna rotation används när höjdskillnaden mellan a-delträd och b-delträd är 2 och höjd C <= höjd L.
4. Stor högerrotation Denna rotation används när höjdskillnaden mellan a-underträd och b-underträd är 2 och höjden på c-underträdet > höjd L.
I varje fall räcker det att helt enkelt bevisa att operationen leder till det önskade resultatet och att den totala höjden minskar med högst 1 och inte kan öka. Ett stort snurr är också en kombination av höger och vänster litet snurr. På grund av balanseringsvillkoret är trädets höjd O(log(N)), där N är antalet hörn, så att lägga till ett element kräver O(log(N))-operationer.
Balansindikatorn kommer att tolkas ytterligare som skillnaden mellan höjden på vänster och höger underträd, och algoritmen kommer att baseras på TAVLTree-typen som beskrivs ovan. Direkt vid insättning (ark) tilldelas ett nollsaldo. Processen att inkludera en vertex består av tre delar (denna process beskrivs av Niklaus Wirth i Algorithms and Data Structures):
Vi återkommer som ett resultat av funktionen om trädets höjd har minskat eller inte. Antag att en process från den vänstra grenen återvänder till föräldern (rekursionen går tillbaka), då är tre fall möjliga: { h l - höjden på det vänstra underträdet, h r - höjden på det högra underträdet } Inkluderande en vertex i det vänstra underträdet kommer att resultera i
I den tredje situationen är det nödvändigt att bestämma balanseringen av det vänstra underträdet. Om det vänstra underträdet i denna vertex (Tree^.left^.left) är högre än det högra (Tree^.left^.right), så krävs en stor högerrotation, annars räcker det med en liten höger. Liknande (symmetriska) resonemang kan ges för införande i det högra underträdet.
För enkelhetens skull beskriver vi en rekursiv raderingsalgoritm. Om vertexet är ett löv, tar vi bort det och kallar balanseringen av alla dess förfäder i ordning från förälder till rot. Annars hittar vi närmaste vertex i värde i underträdet för den högsta höjden (höger eller vänster) och flyttar det till platsen för vertexet som ska raderas, samtidigt som vi anropar borttagningsproceduren.
Låt oss bevisa att denna algoritm bevarar balansen. För att göra detta bevisar vi genom induktion på trädets höjd att efter att ha tagit bort en del vertex från trädet och efterföljande balansering, minskar trädets höjd med högst 1. Basen för induktionen: För ett löv, uppenbarligen sant. Induktionssteg: Antingen bryts inte balansvillkoret vid roten (efter radering kan roten ändras), då har höjden på det givna trädet inte ändrats, eller så har det strikt mindre av underträden minskat => höjden före balansering har inte ändrad => efter det kommer den att minska med högst 1.
Uppenbarligen, som ett resultat av dessa åtgärder, anropas borttagningsproceduren inte mer än 3 gånger, eftersom vertexet som tas bort av det andra anropet inte har ett av underträden. Men att hitta den närmaste kräver O(N) operationer varje gång. Möjligheten till optimering blir uppenbar: sökningen efter närmaste vertex kan utföras längs kanten av underträdet, vilket reducerar komplexiteten till O(log(N)).
En icke-rekursiv algoritm är mer komplicerad än en rekursiv.
För att implementera radering kommer vi att utgå från samma princip som när vi infogar: vi kommer att hitta en vertex, från vilken radering inte kommer att leda till en förändring i dess höjd. Det finns två fall:
För att underlätta förståelsen innehåller ovanstående algoritm inga optimeringar. Till skillnad från den rekursiva algoritmen ersätts den hittade borttagna vertexen med värdet från den vänstra undergrenen. Denna algoritm kan optimeras på samma sätt som den rekursiva (på grund av det faktum att rörelseriktningen är känd efter att ha hittat vertexet som ska tas bort):
Som redan nämnts, om vertexet som ska raderas är ett löv, så tas det bort, och den omvända genomgången av trädet sker från föräldern till det raderade bladet. Om det inte är ett löv, hittas en "ersättning" för det, och den omvända traverseringen av trädet kommer från "ersättningsföräldern". Omedelbart efter avlägsnandet av elementet - "ersättning" tar emot balansen av den borttagna noden.
I omvänd bypass: om de under övergången till föräldern kom från vänster, ökar saldot med 1, om de kom från höger, minskar det med 1.
Detta görs tills balansen ändras till -1 eller 1 (märk skillnaden med att infoga ett element!): i detta fall skulle en sådan balansändring indikera en konstant deltahöjd på underträden. Rotationer följer samma regler som vid insättning.
Beteckna:
Om rotationen sker när ett element sätts in, är pivotens balans antingen 1 eller −1. I det här fallet, efter rotationen, sätts saldonen för båda lika med 0. Vid radering är allt annorlunda: Pivots saldo kan bli lika med 0 (detta är lätt att verifiera).
Här är en sammanfattande tabell över de slutliga balansernas beroende av rotationsriktningen och den initiala balansen för pivotnoden:
Sväng riktning | Gammal pivotbalans | Ny Current.Balance | Ny pivotbalans |
---|---|---|---|
Vänster eller höger | -1 eller +1 | 0 | 0 |
Höger | 0 | -ett | +1 |
Vänster | 0 | +1 | -ett |
Pivot och Current är samma, men en tredje medlem av turn läggs till. Låt oss beteckna det för "Bottom": det är (med en dubbel högersväng) Pivots vänstra son, och med en dubbel vänster - Pivots högra son.
Med denna rotation får Bottom alltid ett saldo på 0 som ett resultat, men arrangemanget av saldon för Pivot och Current beror på dess initiala balans.
Här är en sammanfattande tabell över de slutliga balansernas beroende av rotationsriktningen och den initiala balansen för Bottennoden:
Riktning | Gammal bottenbalans | Ny Current.Balance | Ny pivotbalans |
---|---|---|---|
Vänster eller höger | 0 | 0 | 0 |
Höger | +1 | 0 | -ett |
Höger | -ett | +1 | 0 |
Vänster | +1 | -ett | 0 |
Vänster | -ett | 0 | +1 |
Från formeln ovan kommer höjden på ett AVL-träd aldrig att överstiga höjden på ett perfekt balanserat träd med mer än 45 %. För stora har vi uppskattningen . Att utföra grundläggande operationer kräver således en jämförelseordning. Det har experimentellt visat sig att en balansering sker för varannan inneslutning och för vart femte undantag.
Balanserade (självbalanserande) träd:
Träd (datastruktur) | |
---|---|
Binära träd | |
Självbalanserande binära träd |
|
B-träd | |
prefix träd |
|
Binär uppdelning av utrymme | |
Icke-binära träd |
|
Bryter upp utrymmet |
|
Andra träd |
|
Algoritmer |