AVL træ | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
engelsk A.V.L træ | ||||||||||||||||
Type | søgetræ | |||||||||||||||
Opfindelsens år | 1968 | |||||||||||||||
Forfatter | Adelson-Velsky Georgy Maksimovich og Landis Evgeny Mikhailovich | |||||||||||||||
Kompleksitet i O-symboler | ||||||||||||||||
|
||||||||||||||||
Mediefiler på Wikimedia Commons |
Et AVL-træ er et højdebalanceret binært søgetræ : for hvert af dets hjørner afviger højden af dets to undertræer med højst 1.
AVL er en forkortelse dannet af de første bogstaver af skaberne (sovjetiske videnskabsmænd) Adelson-Velsky Georgy Maksimovich og Landis Evgeny Mikhailovich .
Den maksimale højde af et AVL-træ for et givet antal noder [1] :
hvor:
(runde op)
(rund ned)
(rund ned).
Antallet af mulige højder er meget begrænset i praksis (med 32-bit adressering er den maksimale højde 45, med 48-bit adressering er det 68), så det er nok bedre at forudberegne alle værdierne af minimumsantallet af noder for hver højde ved hjælp af den rekursive formel for Fibonacci-træet :
,
,
.
Mellemværdier for antallet af noder svarer til den tidligere (lavere) højde.
Med hensyn til et AVL-træ er toppunktsbalancering en operation, der, hvis højdeforskellen mellem venstre og højre undertræ = 2, ændrer overordnede-underordnede links i undertræet af dette vertex, så forskellen bliver <= 1, ellers ændrer ikke noget. Det angivne resultat opnås ved rotationer af undertræet i det givne toppunkt.
Der anvendes 4 typer rotationer:
1. Lille venstredrejning Denne rotation bruges, når højdeforskellen mellem a-undertræ og b-undertræ er 2 og højde C <= højde R.
2. Stor venstredrejning Denne rotation bruges, når højdeforskellen mellem a-undertræ og b-undertræ er 2 og højde på c-undertræ > højde R.
3. Lille højrerotation Denne rotation bruges, når højdeforskellen mellem a-undertræ og b-undertræ er 2 og højde C <= højde L.
4. Stor højredrejning Denne rotation bruges, når højdeforskellen mellem a-undertræ og b-undertræ er 2 og højde på c-undertræ > højde L.
I hvert tilfælde er det nok blot at bevise, at operationen fører til det ønskede resultat, og at den samlede højde falder med højst 1 og ikke kan stige. Et stort spin er også en kombination af højre og venstre lille spin. På grund af balanceringstilstanden er højden af træet O(log(N)), hvor N er antallet af hjørner, så tilføjelse af et element kræver O(log(N))-operationer.
Balanceindikatoren vil yderligere blive fortolket som forskellen mellem højden af venstre og højre undertræ, og algoritmen vil være baseret på TAVLTree-typen beskrevet ovenfor. Direkte ved indsættelse (ark) tildeles en nulsaldo. Processen med at inkludere et vertex består af tre dele (denne proces er beskrevet af Niklaus Wirth i Algorithms and Data Structures):
Vi vender tilbage som følge af funktionen om træets højde er faldet eller ej. Antag, at en proces fra venstre gren vender tilbage til forælderen (rekursionen går tilbage), så er tre tilfælde mulige: { h l - højden af venstre undertræ, h r - højden af højre undertræ } Inklusiv et toppunkt i venstre undertræ vil medføre
I den tredje situation er det nødvendigt at bestemme balanceringen af det venstre undertræ. Hvis det venstre undertræ af dette toppunkt (Tree^.left^.left) er højere end det højre (Tree^.left^.right), så er en stor højredrejning påkrævet, ellers vil en lille højrerotation være tilstrækkelig. Lignende (symmetriske) ræsonnementer kan gives for optagelse i det højre undertræ.
For nemheds skyld beskriver vi en rekursiv sletningsalgoritme. Hvis toppunktet er et blad, så sletter vi det og kalder balanceringen af alle dets forfædre i rækkefølge fra forælder til rod. Ellers finder vi det nærmeste toppunkt i værdi i undertræet af den højeste højde (højre eller venstre) og flytter det til stedet for det toppunkt, der skal slettes, mens vi kalder fjernelsesproceduren.
Lad os bevise, at denne algoritme bevarer balancen. For at gøre dette beviser vi ved induktion på højden af træet, at efter at have fjernet noget toppunkt fra træet og efterfølgende afbalancering, falder træets højde med højst 1. Grunden for induktionen: For et blad, åbenbart sandt. Induktionstrin: Enten er balancebetingelsen ved roden (efter sletning kan roden ændres) ikke overtrådt, så er højden af det givne træ ikke ændret, eller det strengt mindre af undertræerne er faldet => højden før balancering har ikke ændret => derefter vil den ikke falde med mere end 1.
Som et resultat af disse handlinger kaldes fjernelsesproceduren naturligvis ikke mere end 3 gange, da toppunktet, der fjernes af det andet kald, ikke har et af undertræerne. Men at finde den nærmeste kræver O(N) operationer hver gang. Muligheden for optimering bliver indlysende: Søgningen efter det nærmeste toppunkt kan udføres langs kanten af undertræet, hvilket reducerer kompleksiteten til O(log(N)).
En ikke-rekursiv algoritme er mere kompliceret end en rekursiv.
For at implementere sletning vil vi gå ud fra det samme princip som ved indsættelse: vi finder et toppunkt, hvor sletning ikke vil føre til en ændring i dets højde. Der er to tilfælde:
For at lette forståelsen indeholder ovenstående algoritme ingen optimeringer. I modsætning til den rekursive algoritme erstattes det fundne fjernede toppunkt med værdien fra venstre undergren. Denne algoritme kan optimeres på samme måde som den rekursive (på grund af det faktum, at efter at have fundet det toppunkt, der skal fjernes, kendes bevægelsesretningen):
Som allerede nævnt, hvis toppunktet, der skal slettes, er et blad, så slettes det, og den omvendte traversering af træet sker fra forælderen til det slettede blad. Hvis ikke et blad, findes en "erstatning" for det, og den omvendte gennemkøring af træet kommer fra "erstatnings"-forælderen. Umiddelbart efter fjernelse af elementet - "udskiftning" modtager saldoen på den fjernede knude.
I omvendt bypass: hvis de under overgangen til forælderen kom fra venstre, øges saldoen med 1, hvis de kom fra højre, falder den med 1.
Dette gøres indtil balancen ændres til -1 eller 1 (bemærk forskellen med at indsætte et element!): i dette tilfælde ville en sådan balanceændring indikere en konstant deltahøjde af undertræerne. Rotationer følger de samme regler som ved indsættelse.
Angiv:
Hvis rotationen sker, når et element indsættes, så er pivotens balance enten 1 eller −1. I dette tilfælde, efter rotationen, sættes saldierne for begge lig med 0. Ved sletning er alt anderledes: Pivots saldo kan blive lig med 0 (dette er let at verificere).
Her er en oversigtstabel over de endelige saldiers afhængighed af rotationsretningen og den indledende balance for pivot-knuden:
Drej retning | Gammel pivotbalance | Ny Current.Balance | Ny pivotbalance |
---|---|---|---|
Venstre eller højre | -1 eller +1 | 0 | 0 |
Ret | 0 | -en | +1 |
Venstre | 0 | +1 | -en |
Pivot og Current er det samme, men et tredje medlem af turn tilføjes. Lad os udpege det til "Bund": det er (med en dobbelt højresving) Pivots venstre søn, og med en dobbelt venstre - Pivots højre søn.
Med denne rotation opnår Bottom altid en balance på 0 som et resultat, men arrangementet af saldi for Pivot og Current afhænger af dens indledende balance.
Her er en oversigtstabel over de endelige saldiers afhængighed af rotationsretningen og den indledende balance for bundknuden:
Retning | Gammel Bundbalance | Ny Current.Balance | Ny pivotbalance |
---|---|---|---|
Venstre eller højre | 0 | 0 | 0 |
Ret | +1 | 0 | -en |
Ret | -en | +1 | 0 |
Venstre | +1 | -en | 0 |
Venstre | -en | 0 | +1 |
Ud fra formlen ovenfor vil højden af et AVL-træ aldrig overstige højden af et perfekt afbalanceret træ med mere end 45 %. For store har vi skønnet . Udførelse af grundlæggende operationer kræver således en rækkefølge af sammenligninger. Det er eksperimentelt blevet fundet, at der sker en balancering for hver 2 inklusioner og for hver 5 undtagelser.
Balancerede (selvbalancerende) træer:
Træ (datastruktur) | |
---|---|
Binære træer | |
Selvbalancerende binære træer |
|
B-træer | |
præfiks træer |
|
Binær opdeling af rummet | |
Ikke-binære træer |
|
At bryde rummet op |
|
Andre træer |
|
Algoritmer |
|