Introducció als Arbres AVL
Els arbres AVL són un tipus especial d'arbre binari de cerca (BST) que es mantenen equilibrats automàticament. El nom AVL prové dels seus inventors, Adelson-Velsky i Landis, que els van introduir el 1962. La característica clau dels arbres AVL és que per a qualsevol node de l'arbre, la diferència de profunditat entre els seus subarbres esquerre i dret (anomenada factor d'equilibri) és com a màxim 1. Això garanteix que les operacions de cerca, inserció i eliminació es puguin realitzar en temps logarítmic.
Característiques dels Arbres AVL
- Equilibri: La diferència de profunditat entre els subarbres esquerre i dret de qualsevol node és com a màxim 1.
- Temps d'operació: Les operacions de cerca, inserció i eliminació es realitzen en O(log n) en el pitjor dels casos.
- Rotacions: Per mantenir l'equilibri, els arbres AVL utilitzen rotacions simples i dobles.
Rotacions en Arbres AVL
Quan es realitza una inserció o eliminació que desequilibra l'arbre, es necessiten rotacions per restaurar l'equilibri. Hi ha quatre tipus de rotacions:
- Rotació Simple a l'Esquerra (LL): Quan un node es desequilibra a l'esquerra a causa d'una inserció en el subarbre esquerre del seu fill esquerre.
- Rotació Simple a la Dreta (RR): Quan un node es desequilibra a la dreta a causa d'una inserció en el subarbre dret del seu fill dret.
- Rotació Doble a l'Esquerra-Dreta (LR): Quan un node es desequilibra a l'esquerra a causa d'una inserció en el subarbre dret del seu fill esquerre.
- Rotació Doble a la Dreta-Esquerra (RL): Quan un node es desequilibra a la dreta a causa d'una inserció en el subarbre esquerre del seu fill dret.
Exemple de Rotació Simple a la Dreta (RR)
Considerem un arbre AVL desequilibrat després d'una inserció:
Després d'una rotació simple a la dreta, l'arbre es converteix en:
Exemple de Rotació Doble a l'Esquerra-Dreta (LR)
Considerem un arbre AVL desequilibrat després d'una inserció:
Després d'una rotació doble a l'esquerra-dreta, l'arbre es converteix en:
Implementació d'un Arbre AVL en Python
A continuació es mostra una implementació bàsica d'un arbre AVL en Python:
class Node:
def __init__(self, key):
self.key = key
self.left = None
self.right = None
self.height = 1
class AVLTree:
def insert(self, root, key):
if not root:
return Node(key)
elif key < root.key:
root.left = self.insert(root.left, key)
else:
root.right = self.insert(root.right, key)
root.height = 1 + max(self.get_height(root.left), self.get_height(root.right))
balance = self.get_balance(root)
if balance > 1 and key < root.left.key:
return self.right_rotate(root)
if balance < -1 and key > root.right.key:
return self.left_rotate(root)
if balance > 1 and key > root.left.key:
root.left = self.left_rotate(root.left)
return self.right_rotate(root)
if balance < -1 and key < root.right.key:
root.right = self.right_rotate(root.right)
return self.left_rotate(root)
return root
def left_rotate(self, z):
y = z.right
T2 = y.left
y.left = z
z.right = T2
z.height = 1 + max(self.get_height(z.left), self.get_height(z.right))
y.height = 1 + max(self.get_height(y.left), self.get_height(y.right))
return y
def right_rotate(self, z):
y = z.left
T3 = y.right
y.right = z
z.left = T3
z.height = 1 + max(self.get_height(z.left), self.get_height(z.right))
y.height = 1 + max(self.get_height(y.left), self.get_height(y.right))
return y
def get_height(self, root):
if not root:
return 0
return root.height
def get_balance(self, root):
if not root:
return 0
return self.get_height(root.left) - self.get_height(root.right)
def pre_order(self, root):
if not root:
return
print("{0} ".format(root.key), end="")
self.pre_order(root.left)
self.pre_order(root.right)
# Exemple d'ús
avl = AVLTree()
root = None
keys = [10, 20, 30, 40, 50, 25]
for key in keys:
root = avl.insert(root, key)
print("Preordre de l'arbre AVL:")
avl.pre_order(root)Explicació del Codi
- Node: La classe
Nodedefineix un node de l'arbre AVL amb una clau, referències als fills esquerre i dret, i la seva alçada. - AVLTree: La classe
AVLTreeconté mètodes per inserir nodes, realitzar rotacions, obtenir l'alçada i el factor d'equilibri dels nodes, i imprimir l'arbre en preordre. - Inserció: El mètode
insertinsereix un nou node a l'arbre i ajusta les alçades i els equilibris mitjançant rotacions si és necessari. - Rotacions: Els mètodes
left_rotateiright_rotaterealitzen les rotacions necessàries per mantenir l'arbre equilibrat. - Preordre: El mètode
pre_orderimprimeix l'arbre en preordre per verificar la seva estructura.
Exercici Pràctic
Exercici
Implementa una funció per eliminar un node d'un arbre AVL i mantenir l'equilibri de l'arbre.
Solució
class AVLTree:
# ... (altres mètodes)
def delete(self, root, key):
if not root:
return root
if key < root.key:
root.left = self.delete(root.left, key)
elif key > root.key:
root.right = self.delete(root.right, key)
else:
if root.left is None:
temp = root.right
root = None
return temp
elif root.right is None:
temp = root.left
root = None
return temp
temp = self.get_min_value_node(root.right)
root.key = temp.key
root.right = self.delete(root.right, temp.key)
if root is None:
return root
root.height = 1 + max(self.get_height(root.left), self.get_height(root.right))
balance = self.get_balance(root)
if balance > 1 and self.get_balance(root.left) >= 0:
return self.right_rotate(root)
if balance > 1 and self.get_balance(root.left) < 0:
root.left = self.left_rotate(root.left)
return self.right_rotate(root)
if balance < -1 and self.get_balance(root.right) <= 0:
return self.left_rotate(root)
if balance < -1 and self.get_balance(root.right) > 0:
root.right = self.right_rotate(root.right)
return self.left_rotate(root)
return root
def get_min_value_node(self, root):
if root is None or root.left is None:
return root
return self.get_min_value_node(root.left)
# Exemple d'ús
avl = AVLTree()
root = None
keys = [10, 20, 30, 40, 50, 25]
for key in keys:
root = avl.insert(root, key)
print("Preordre de l'arbre AVL abans de l'eliminació:")
avl.pre_order(root)
root = avl.delete(root, 40)
print("\nPreordre de l'arbre AVL després de l'eliminació:")
avl.pre_order(root)Explicació del Codi
- Eliminació: El mètode
deleteelimina un node de l'arbre AVL i ajusta les alçades i els equilibris mitjançant rotacions si és necessari. - Node amb Valor Mínim: El mètode
get_min_value_nodetroba el node amb el valor mínim en un subarbre, utilitzat per substituir el node eliminat.
Conclusió
Els arbres AVL són una estructura de dades poderosa que garanteix operacions eficients en temps logarítmic mantenint l'equilibri de l'arbre. Comprendre les rotacions i la implementació d'arbres AVL és essencial per a qualsevol programador que treballi amb estructures de dades avançades.
Curs d'Estructures de Dades
Mòdul 1: Introducció a les Estructures de Dades
- Què són les Estructures de Dades?
- Importància de les Estructures de Dades en la Programació
- Tipus d'Estructures de Dades
Mòdul 2: Llistes
- Introducció a les Llistes
- Llistes Enllaçades
- Llistes Doblement Enllaçades
- Llistes Circulars
- Exercicis amb Llistes
Mòdul 3: Piles
- Introducció a les Piles
- Operacions Bàsiques amb Piles
- Implementació de Piles
- Aplicacions de les Piles
- Exercicis amb Piles
Mòdul 4: Cues
- Introducció a les Cues
- Operacions Bàsiques amb Cues
- Cues Circulars
- Cues de Prioritat
- Exercicis amb Cues
Mòdul 5: Arbres
- Introducció als Arbres
- Arbres Binàries
- Arbres Binàries de Cerca
- Arbres AVL
- Arbres B
- Exercicis amb Arbres
Mòdul 6: Grafs
- Introducció als Grafs
- Representació de Grafs
- Algoritmes de Cerca en Grafs
- Algoritmes de Camins Mínims
- Aplicacions dels Grafs
- Exercicis amb Grafs
