AVL-træ
TræEt selvbalancerende binært søgetræ hvor højdeforskellen mellem venstre og højre undertræ er maksimalt 1.
Kompleksitet
| Operation | Tidskompleksitet |
|---|---|
| Access | O(log n) |
| Search | O(log n) |
| Insertion | O(log n) |
| Deletion | O(log n) |
Beskrivelse
AVL-træet er opkaldt efter opfinderne Adelson-Velsky og Landis og var det første selvbalancerende binære søgetræ der blev opfundet. I et AVL-træ holdes træet balanceret ved at sikre at balancefaktoren (højde af venstre undertræ minus højre undertræ) for hver node er -1, 0 eller 1. Når balancefaktoren bliver udenfor dette interval efter indsættelse eller sletning, anvendes rotationer for at genbalancere træet. Der findes fire typer rotationer: Venstre-Venstre (enkelt højrerotation), Højre-Højre (enkelt venstrerotation), Venstre-Højre (dobbelt rotation) og Højre-Venstre (dobbelt rotation). AVL-træer garanterer O(log n) tid for søgning, indsættelse og sletning fordi træet altid er perfekt balanceret. Dette gør AVL-træer ideelle til applikationer hvor opslag er meget hyppigere end indsættelser og sletninger. Sammenlignet med Red-Black-træer er AVL-træer mere strikt balancerede, hvilket giver hurtigere søgninger men langsommere indsættelser og sletninger pga. flere rotationer.
Kode Eksempel
// JavaScript AVL Tree Implementation
class AVLNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
this.height = 1;
}
}
class AVLTree {
constructor() {
this.root = null;
}
height(node) {
return node ? node.height : 0;
}
getBalance(node) {
return node ? this.height(node.left) - this.height(node.right) : 0;
}
rightRotate(y) {
const x = y.left;
const T2 = x.right;
x.right = y;
y.left = T2;
y.height = Math.max(this.height(y.left), this.height(y.right)) + 1;
x.height = Math.max(this.height(x.left), this.height(x.right)) + 1;
return x;
}
leftRotate(x) {
const y = x.right;
const T2 = y.left;
y.left = x;
x.right = T2;
x.height = Math.max(this.height(x.left), this.height(x.right)) + 1;
y.height = Math.max(this.height(y.left), this.height(y.right)) + 1;
return y;
}
insert(node, value) {
if (!node) return new AVLNode(value);
if (value < node.value) {
node.left = this.insert(node.left, value);
} else if (value > node.value) {
node.right = this.insert(node.right, value);
} else {
return node; // Duplikater ikke tilladt
}
node.height = 1 + Math.max(this.height(node.left), this.height(node.right));
const balance = this.getBalance(node);
// Venstre-Venstre tilfælde
if (balance > 1 && value < node.left.value) {
return this.rightRotate(node);
}
// Højre-Højre tilfælde
if (balance < -1 && value > node.right.value) {
return this.leftRotate(node);
}
// Venstre-Højre tilfælde
if (balance > 1 && value > node.left.value) {
node.left = this.leftRotate(node.left);
return this.rightRotate(node);
}
// Højre-Venstre tilfælde
if (balance < -1 && value < node.right.value) {
node.right = this.rightRotate(node.right);
return this.leftRotate(node);
}
return node;
}
add(value) {
this.root = this.insert(this.root, value);
}
search(node, value) {
if (!node) return false;
if (value === node.value) return true;
if (value < node.value) return this.search(node.left, value);
return this.search(node.right, value);
}
find(value) {
return this.search(this.root, value);
}
}
// Brug
const tree = new AVLTree();
tree.add(10);
tree.add(20);
tree.add(30); // Udløser rotation
tree.add(40);
tree.add(50);
console.log(tree.find(30)); // trueAnvendelsesområder
- •Hukommelsesbaseret sortering med hyppige opslag
- •Ordnede data med sjældne opdateringer
- •Databaseindeksering hvor læseydelse er kritisk
- •Autofuldførelse og typeahead-funktioner
- •Intervalforespørgsler på sorterede data
Fordele
- ✓Garanteret O(log n) for alle operationer
- ✓Mere strikt balanceret end Red-Black-træer
- ✓Hurtigere søgninger end andre balancerede træer
- ✓Opretholder sorteret rækkefølge
- ✓God cache-lokalitet pga. balance
Ulemper
- ✗Flere rotationer end Red-Black-træer ved indsættelse/sletning
- ✗Mere kompleks implementering
- ✗Ekstra hukommelse til at gemme højdeinformation
- ✗Langsommere indsættelser end Red-Black-træer
- ✗Rebalanceringsomkostninger kan være betydelige
Eksempler fra den virkelige verden
- •Databaseindekser hvor opslag er hyppige (banksystemer)
- •Sorteringsalgoritmer i Java Collections TreeMap
- •Hukommelsesbaserede caches med ordnede nøgler
- •Symboltabeller i compilere
- •Telefonbøger med hurtig navnesøgning