arborele AVL | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Engleză A.V.L arbore | ||||||||||||||||
Tip de | arborele de căutare | |||||||||||||||
Anul inventiei | 1968 | |||||||||||||||
Autor | Adelson-Velsky Georgy Maksimovici și Landis Evgeny Mihailovici | |||||||||||||||
Complexitatea în simbolurile O | ||||||||||||||||
|
||||||||||||||||
Fișiere media la Wikimedia Commons |
Un arbore AVL este un arbore de căutare binar echilibrat pe înălțime : pentru fiecare dintre vârfurile sale, înălțimea celor doi subarbori diferă cu cel mult 1.
AVL este o abreviere formată din primele litere ale creatorilor (oameni de știință sovietici) Adelson-Velsky Georgy Maksimovici și Landis Evgeny Mikhailovici .
Înălțimea maximă a unui arbore AVL pentru un număr dat de noduri [1] :
Unde:
(ridica)
(rotunjind in jos)
(rotunjind în jos).
Numărul de înălțimi posibile este foarte limitat în practică (cu adresare pe 32 de biți, înălțimea maximă este de 45, cu adresare pe 48 de biți este de 68), așa că probabil este mai bine să precalculați toate valorile numărului minim de noduri pentru fiecare înălțime folosind formula recursivă pentru arborele Fibonacci :
,
,
.
Valorile intermediare ale numărului de noduri vor corespunde înălțimii anterioare (inferioare).
În ceea ce privește un arbore AVL, echilibrarea vârfurilor este o operație care, dacă diferența de înălțime a subarborilor din stânga și din dreapta = 2, schimbă legăturile părinte-copil din subarborele acestui vârf, astfel încât diferența să devină <= 1, în caz contrar, nu schimba nimic. Rezultatul indicat se obține prin rotații ale subarborelui vârfului dat.
Se folosesc 4 tipuri de rotații:
1. Rotație mică la stânga Această rotație este utilizată atunci când diferența de înălțime dintre subarborele a și subarborele b este 2 și înălțimea C <= înălțimea R.
2. Rotație mare la stânga Această rotație este folosită atunci când diferența de înălțime dintre subarborele a și subarborele b este 2 și înălțimea subarborelui c > înălțimea R.
3. Rotație mică la dreapta Această rotație este utilizată atunci când diferența de înălțime dintre subarborele a și subarborele b este 2 și înălțimea C <= înălțimea L.
4. Rotație mare la dreapta Această rotație este utilizată atunci când diferența de înălțime dintre subarborele a și subarborele b este 2 și înălțimea subarborelui c > înălțimea L.
În fiecare caz, este suficient să demonstrați pur și simplu că operația duce la rezultatul dorit și că înălțimea totală scade cu cel mult 1 și nu poate crește. De asemenea, o rotire mare este o combinație de rotire mică la dreapta și la stânga. Din cauza condiției de echilibrare, înălțimea arborelui este O(log(N)), unde N este numărul de vârfuri, deci adăugarea unui element necesită operații O(log(N)).
Indicatorul de echilibru va fi interpretat în continuare ca diferența dintre înălțimea subarborilor din stânga și din dreapta, iar algoritmul se va baza pe tipul TAVLTree descris mai sus. Direct la introducere (foaia) i se atribuie un sold zero. Procesul de includere a unui vârf constă din trei părți (acest proces este descris de Niklaus Wirth în Algoritmi și structuri de date):
Vom reveni ca rezultat al funcției dacă înălțimea copacului a scăzut sau nu. Să presupunem că un proces din ramura stângă revine la părinte (recursiunea se întoarce), atunci sunt posibile trei cazuri: { h l - înălțimea subarborelului din stânga, h r - înălțimea subarborelui din dreapta } Includerea unui vârf în subarborele din stânga va avea ca rezultat
În a treia situație, este necesar să se determine echilibrarea subarborelui din stânga. Dacă subarborele din stânga acestui vârf (Tree^.left^.left) este mai mare decât cel din dreapta (Tree^.left^.right), atunci este necesară o rotație mare la dreapta, altfel va fi suficientă una mică la dreapta. Raționament similar (simetric) poate fi dat pentru includerea în subarborele din dreapta.
Pentru simplitate, descriem un algoritm de ștergere recursiv. Dacă vârful este o frunză, atunci îl ștergem și numim echilibrarea tuturor strămoșilor săi în ordine de la părinte la rădăcină. În caz contrar, găsim cel mai apropiat vârf în valoare în subarborele cu cea mai mare înălțime (dreapta sau stânga) și îl mutăm în locul vârfului de șters, în timp ce apelăm procedura de eliminare.
Să demonstrăm că acest algoritm păstrează echilibrul. Pentru aceasta, demonstrăm prin inducție asupra înălțimii arborelui că după îndepărtarea unor vârfuri din arbore și echilibrarea ulterioară, înălțimea arborelui scade cu cel mult 1. Baza inducției: Pentru o frunză, evident adevărat. Etapa de inducție: Fie condiția de echilibru la rădăcină (după ștergere, rădăcina se poate schimba) nu este încălcată, atunci înălțimea arborelui dat nu s-a schimbat, fie cel strict mai mic dintre subarbori a scăzut => înălțimea înainte de echilibrare a scăzut neschimbat => după aceea va scădea cu cel mult 1.
Evident, ca urmare a acestor acțiuni, procedura de eliminare este apelată de cel mult 3 ori, deoarece vârful eliminat de al doilea apel nu are niciunul dintre subarbori. Dar găsirea celui mai apropiat necesită operații O(N) de fiecare dată. Posibilitatea de optimizare devine evidentă: căutarea celui mai apropiat vârf poate fi efectuată de-a lungul marginii subarborelui, ceea ce reduce complexitatea la O(log(N)).
Un algoritm nerecursiv este mai complicat decât unul recursiv.
Pentru a implementa ștergerea, vom proceda de la același principiu ca și la inserare: vom găsi un vârf, ștergerea din care nu va duce la modificarea înălțimii sale. Există două cazuri:
Pentru ușurință de înțelegere, algoritmul de mai sus nu conține nicio optimizare. Spre deosebire de algoritmul recursiv, vârful eliminat găsit este înlocuit cu valoarea din subramura stângă. Acest algoritm poate fi optimizat în același mod ca și cel recursiv (datorită faptului că după găsirea vârfului de îndepărtat se cunoaște direcția de mișcare):
După cum sa menționat deja, dacă vârful care trebuie șters este o frunză, atunci acesta este șters, iar traversarea inversă a arborelui are loc de la părintele frunzei șterse. Dacă nu o frunză, se găsește un „înlocuitor” pentru ea, iar traversarea inversă a arborelui vine de la părintele „înlocuitor”. Imediat după îndepărtarea elementului - „înlocuirea” primește soldul nodului eliminat.
În bypass invers: dacă în timpul trecerii la părinte au venit din stânga, soldul crește cu 1, dacă au venit din dreapta, scade cu 1.
Acest lucru se face până când echilibrul se schimbă la -1 sau 1 (observați diferența cu inserarea unui element!): în acest caz, o astfel de modificare a echilibrului ar indica o înălțime constantă a deltei subarborilor. Rotațiile urmează aceleași reguli ca la introducere.
Denota:
Dacă rotația are loc atunci când un element este inserat, atunci echilibrul pivotului este fie 1, fie -1. În acest caz, după rotație, soldurile ambelor sunt setate egale cu 0. La ștergere, totul este diferit: soldul lui Pivot poate deveni egal cu 0 (acest lucru este ușor de verificat).
Iată un tabel rezumativ al dependenței balanțelor finale de direcția de rotație și echilibrul inițial al nodului Pivot:
Direcția de întoarcere | Vechiul Balanță Pivot | Curent nou.Balance | Noul echilibru Pivot |
---|---|---|---|
Stanga sau dreapta | -1 sau +1 | 0 | 0 |
Dreapta | 0 | -unu | +1 |
Stânga | 0 | +1 | -unu |
Pivot și Current sunt aceleași, dar se adaugă un al treilea membru al turnului. Să-l desemnăm pentru „Jos”: este (cu o viraj dublă la dreapta) fiul stâng al lui Pivot, iar cu o stânga dublă - fiul drept al lui Pivot.
Cu această rotație, Bottom dobândește întotdeauna un echilibru de 0 ca rezultat, dar aranjarea soldurilor pentru Pivot și Current depinde de soldul său inițial.
Iată un tabel rezumativ al dependenței balanțelor finale de sensul de rotație și echilibrul inițial al nodului de jos:
Direcţie | Echilibrul de jos vechi | Curent nou.Balance | Noul echilibru Pivot |
---|---|---|---|
Stanga sau dreapta | 0 | 0 | 0 |
Dreapta | +1 | 0 | -unu |
Dreapta | -unu | +1 | 0 |
Stânga | +1 | -unu | 0 |
Stânga | -unu | 0 | +1 |
Din formula de mai sus, înălțimea unui arbore AVL nu va depăși niciodată înălțimea unui arbore perfect echilibrat cu mai mult de 45%. Pentru mari , avem estimarea . Astfel, efectuarea operațiilor de bază necesită o ordine a comparațiilor. Sa constatat experimental că are loc o echilibrare pentru fiecare 2 incluziuni și pentru fiecare 5 excepții.
Copaci echilibrați (auto-echilibrați):
Arborele (structura de date) | |
---|---|
Arbori binari | |
Arbori binari cu auto-echilibrare |
|
B-copaci |
|
arbori de prefix |
|
Partiționarea binară a spațiului | |
Arbori non-binari |
|
Despărțirea spațiului |
|
Alți copaci |
|
Algoritmi |