У цьому підручнику ви дізнаєтеся, що таке авл-дерево. Крім того, ви знайдете робочі приклади різних операцій, виконуваних над avl-деревом на C, C ++, Java та Python.
Дерево AVL - це самозбалансоване двійкове дерево пошуку, в якому кожен вузол підтримує додаткову інформацію, звану коефіцієнтом балансу, значення якої дорівнює -1, 0 або +1.
Дерево AVL отримало свою назву на честь його винахідника Георгія Адельсона-Вельського та Ландіса.
Фактор балансу
Коефіцієнт балансу вузла у дереві AVL - це різниця між висотою лівого піддерева та висоти правого піддерева цього вузла.
Балансовий коефіцієнт = (Висота лівого піддерева - Висота правого піддерева) або (Висота правого піддерева - Висота лівого піддерева)
Властивість самобалансування дерева avl підтримується коефіцієнтом балансу. Значення коефіцієнта залишку завжди має бути -1, 0 або +1.
Прикладом збалансованого дерева avl є:

Операції над деревом AVL
Різні операції, які можна виконати на дереві AVL:
Обертання піддерев у дереві AVL
При операції обертання положення вузлів піддерева змінюються між собою.
Існує два типи обертань:
Поворот вліво
При обертанні ліворуч розташування вузлів праворуч трансформується в розташування лівого вузла.
Алгоритм
- Нехай початкове дерево буде:
Обертати вліво
- Якщо y має ліве піддерево, призначте x батьківським для лівого піддерева y.
Призначте x батьківським елементом лівого піддерева y
- Якщо батьківським є x
NULL
, зробіть y коренем дерева. - В іншому випадку, якщо x - ліва дочірня частина p, зробіть y лівою дочірньою частиною p.
- В іншому випадку призначте y як правильну дочірню сторінку с.
Змініть батьківський x на y
- Зробіть y батьківським для x.
Призначте y як батьківський елемент x.
Повернути вправо
При обертанні ліворуч розташування вузлів зліва перетворюється на розташування на правому вузлі.
- Нехай початкове дерево буде:
Початкове дерево
- Якщо x має праве піддерево, призначте y як батьківського для правого піддерева x.
Призначте y як батьківський для правого піддерева x
- Якщо батьком y є
NULL
, зробіть x коренем дерева. - В іншому випадку, якщо y є правильним нащадком свого батьківського p, зробіть x правильним нащадком p.
- В іншому випадку призначте x як ліву дочірню сторінку p.
Призначте батьківського елемента y як батьківського елемента x.
- Зробити x батьківським елементом y.
Призначте x батьківським елементом y
Поворот вліво-вправо та вправо-вліво
При обертанні вліво-вправо розташування спочатку зміщуються вліво, а потім вправо.
- Зробіть обертання ліворуч на xy.
Обертати ліворуч xy
- Зробіть обертання вправо на yz.
Повернути zy вправо
При обертанні праворуч-ліво розташування спочатку зміщується вправо, а потім вліво.
- Зробіть обертання вправо на xy.
Повернути вправо xy
- Зробіть обертання ліворуч на zy.
Обертати ліворуч zy
Алгоритм вставки новогоНода
Новий Вузол завжди вставляється як листовий вузол з коефіцієнтом балансу, рівним 0.
- Нехай початкове дерево буде:
Початкове дерево для вставки
Нехай вузол, який потрібно вставити, буде:Новий вузол
- Перейдіть до відповідного листового вузла, щоб вставити newNode, використовуючи наступні рекурсивні кроки. Порівняйте newKey з rootKey поточного дерева.
- Якщо newKey <rootKey, викличте алгоритм вставки в лівому піддереві поточного вузла, поки не буде досягнутий листовий вузол.
- В іншому випадку, якщо newKey> rootKey, викличте алгоритм вставки виклику в правому піддереві поточного вузла, поки не буде досягнутий вузол листа.
- В іншому випадку поверніть leafNode.
Пошук місця для вставки newNode
- Порівняйте leafKey, отриманий із наведених вище кроків, з newKey:
- Якщо newKey <leafKey, зробіть newNode як leftChild of leafNode.
- В іншому випадку створити newNode як rightChild of leafNode.
Вставка нового вузла
- Оновити баланс фактора вузлів.
Оновлення коефіцієнта балансу після вставки
- Якщо вузли незбалансовані, то перебалансуйте вузол.
- Якщо balanceFactor> 1, це означає, що висота лівого піддерева більша, ніж висота правого піддерева. Отже, робіть обертання вправо або вліво-вправо
- Якщо newNodeKey <leftChildKey, робіть обертання вправо.
- В іншому випадку робіть обертання вліво-вправо.
Врівноваження дерева з обертанням
Врівноваження дерева з обертанням
- Якщо balanceFactor <-1, це означає, що висота правого піддерева більша, ніж висота лівого піддерева. Отже, робіть обертання вправо або вправо-вліво
- Якщо newNodeKey> rightChildKey, робіть обертання ліворуч.
- В іншому випадку робіть обертання вправо-вліво
- Якщо balanceFactor> 1, це означає, що висота лівого піддерева більша, ніж висота правого піддерева. Отже, робіть обертання вправо або вліво-вправо
- Остаточне дерево:
Остаточне збалансоване дерево
Алгоритм видалення вузла
Вузол завжди видаляється як листовий вузол. Після видалення вузла фактори балансу вузлів змінюються. Для того, щоб збалансувати коефіцієнт балансу, виконуються відповідні обертання.
- Знайдіть nodeToBeDeleted (рекурсія використовується для пошуку nodeToBeDeleted у коді, що використовується нижче).
Пошук вузла, який потрібно видалити
- Існує три випадки видалення вузла:
- Якщо nodeToBeDeleted є листовим вузлом (тобто не має жодної дочірньої організації), то видаліть nodeToBeDeleted.
- Якщо nodeToBeDeleted має одну дочірню організацію, тоді підставте вміст nodeToBeDeleted вмістом дочірньої організації. Видаліть дитину.
- Якщо nodeToBeDeleted має двох дочірніх організацій, знайдіть наступника inorder w з nodeToBeDeleted (тобто. Вузол з мінімальним значенням ключа в правому піддереві).
Пошук наступника
- Замініть вміст nodeToBeDeleted на вміст w.
Підставте вузол, який потрібно видалити
- Видалити листовий вузол w.
Видалити w
- Замініть вміст nodeToBeDeleted на вміст w.
- Оновити баланс фактора вузлів.
Оновлення bf
- Збалансуйте дерево, якщо коефіцієнт балансу будь-якого з вузлів не дорівнює -1, 0 або 1.
- Якщо balanceFactor поточногоNode> 1,
- Якщо balanceFactor leftChild> = 0, виконайте обертання праворуч.
Поверніть праворуч для балансування дерева
- В іншому випадку робіть обертання вліво-вправо.
- Якщо balanceFactor leftChild> = 0, виконайте обертання праворуч.
- Якщо balanceFactor поточногоNode <-1,
- Якщо balanceFactor rightChild <= 0, виконайте обертання ліворуч.
- В іншому випадку робіть обертання вправо-вліво.
- Якщо balanceFactor поточногоNode> 1,
- Остаточне дерево:
Avl tree final
Приклади Python, Java та C / C ++
Python Java C C ++ # AVL tree implementation in Python import sys # Create a tree node class TreeNode(object): def __init__(self, key): self.key = key self.left = None self.right = None self.height = 1 class AVLTree(object): # Function to insert a node def insert_node(self, root, key): # Find the correct location and insert the node if not root: return TreeNode(key) elif key 1: if key < root.left.key: return self.rightRotate(root) else: root.left = self.leftRotate(root.left) return self.rightRotate(root) if balanceFactor root.right.key: return self.leftRotate(root) else: root.right = self.rightRotate(root.right) return self.leftRotate(root) return root # Function to delete a node def delete_node(self, root, key): # Find the node to be deleted and remove it if not root: return root elif key root.key: root.right = self.delete_node(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.getMinValueNode(root.right) root.key = temp.key root.right = self.delete_node(root.right, temp.key) if root is None: return root # Update the balance factor of nodes root.height = 1 + max(self.getHeight(root.left), self.getHeight(root.right)) balanceFactor = self.getBalance(root) # Balance the tree if balanceFactor> 1: if self.getBalance(root.left)>= 0: return self.rightRotate(root) else: root.left = self.leftRotate(root.left) return self.rightRotate(root) if balanceFactor < -1: if self.getBalance(root.right) <= 0: return self.leftRotate(root) else: root.right = self.rightRotate(root.right) return self.leftRotate(root) return root # Function to perform left rotation def leftRotate(self, z): y = z.right T2 = y.left y.left = z z.right = T2 z.height = 1 + max(self.getHeight(z.left), self.getHeight(z.right)) y.height = 1 + max(self.getHeight(y.left), self.getHeight(y.right)) return y # Function to perform right rotation def rightRotate(self, z): y = z.left T3 = y.right y.right = z z.left = T3 z.height = 1 + max(self.getHeight(z.left), self.getHeight(z.right)) y.height = 1 + max(self.getHeight(y.left), self.getHeight(y.right)) return y # Get the height of the node def getHeight(self, root): if not root: return 0 return root.height # Get balance factore of the node def getBalance(self, root): if not root: return 0 return self.getHeight(root.left) - self.getHeight(root.right) def getMinValueNode(self, root): if root is None or root.left is None: return root return self.getMinValueNode(root.left) def preOrder(self, root): if not root: return print("(0) ".format(root.key), end="") self.preOrder(root.left) self.preOrder(root.right) # Print the tree def printHelper(self, currPtr, indent, last): if currPtr != None: sys.stdout.write(indent) if last: sys.stdout.write("R----") indent += " " else: sys.stdout.write("L----") indent += "| " print(currPtr.key) self.printHelper(currPtr.left, indent, False) self.printHelper(currPtr.right, indent, True) myTree = AVLTree() root = None nums = (33, 13, 52, 9, 21, 61, 8, 11) for num in nums: root = myTree.insert_node(root, num) myTree.printHelper(root, "", True) key = 13 root = myTree.delete_node(root, key) print("After Deletion: ") myTree.printHelper(root, "", True)
// AVL tree implementation in Java // Create node class Node ( int item, height; Node left, right; Node(int d) ( item = d; height = 1; ) ) // Tree class class AVLTree ( Node root; int height(Node N) ( if (N == null) return 0; return N.height; ) int max(int a, int b) ( return (a> b) ? a : b; ) Node rightRotate(Node y) ( Node x = y.left; Node T2 = x.right; x.right = y; y.left = T2; y.height = max(height(y.left), height(y.right)) + 1; x.height = max(height(x.left), height(x.right)) + 1; return x; ) Node leftRotate(Node x) ( Node y = x.right; Node T2 = y.left; y.left = x; x.right = T2; x.height = max(height(x.left), height(x.right)) + 1; y.height = max(height(y.left), height(y.right)) + 1; return y; ) // Get balance factor of a node int getBalanceFactor(Node N) ( if (N == null) return 0; return height(N.left) - height(N.right); ) // Insert a node Node insertNode(Node node, int item) ( // Find the position and insert the node if (node == null) return (new Node(item)); if (item node.item) node.right = insertNode(node.right, item); else return node; // Update the balance factor of each node // And, balance the tree node.height = 1 + max(height(node.left), height(node.right)); int balanceFactor = getBalanceFactor(node); if (balanceFactor> 1) ( if (item node.left.item) ( node.left = leftRotate(node.left); return rightRotate(node); ) ) if (balanceFactor node.right.item) ( return leftRotate(node); ) else if (item < node.right.item) ( node.right = rightRotate(node.right); return leftRotate(node); ) ) return node; ) Node nodeWithMimumValue(Node node) ( Node current = node; while (current.left != null) current = current.left; return current; ) // Delete a node Node deleteNode(Node root, int item) ( // Find the node to be deleted and remove it if (root == null) return root; if (item root.item) root.right = deleteNode(root.right, item); else ( if ((root.left == null) || (root.right == null)) ( Node temp = null; if (temp == root.left) temp = root.right; else temp = root.left; if (temp == null) ( temp = root; root = null; ) else root = temp; ) else ( Node temp = nodeWithMimumValue(root.right); root.item = temp.item; root.right = deleteNode(root.right, temp.item); ) ) if (root == null) return root; // Update the balance factor of each node and balance the tree root.height = max(height(root.left), height(root.right)) + 1; int balanceFactor = getBalanceFactor(root); if (balanceFactor> 1) ( if (getBalanceFactor(root.left)>= 0) ( return rightRotate(root); ) else ( root.left = leftRotate(root.left); return rightRotate(root); ) ) if (balanceFactor < -1) ( if (getBalanceFactor(root.right) <= 0) ( return leftRotate(root); ) else ( root.right = rightRotate(root.right); return leftRotate(root); ) ) return root; ) void preOrder(Node node) ( if (node != null) ( System.out.print(node.item + " "); preOrder(node.left); preOrder(node.right); ) ) // Print the tree private void printTree(Node currPtr, String indent, boolean last) ( if (currPtr != null) ( System.out.print(indent); if (last) ( System.out.print("R----"); indent += " "; ) else ( System.out.print("L----"); indent += "| "; ) System.out.println(currPtr.item); printTree(currPtr.left, indent, false); printTree(currPtr.right, indent, true); ) ) // Driver code public static void main(String() args) ( AVLTree tree = new AVLTree(); tree.root = tree.insertNode(tree.root, 33); tree.root = tree.insertNode(tree.root, 13); tree.root = tree.insertNode(tree.root, 53); tree.root = tree.insertNode(tree.root, 9); tree.root = tree.insertNode(tree.root, 21); tree.root = tree.insertNode(tree.root, 61); tree.root = tree.insertNode(tree.root, 8); tree.root = tree.insertNode(tree.root, 11); tree.printTree(tree.root, "", true); tree.root = tree.deleteNode(tree.root, 13); System.out.println("After Deletion: "); tree.printTree(tree.root, "", true); ) )
// AVL tree implementation in C #include #include // Create Node struct Node ( int key; struct Node *left; struct Node *right; int height; ); int max(int a, int b); // Calculate height int height(struct Node *N) ( if (N == NULL) return 0; return N->height; ) int max(int a, int b) ( return (a> b) ? a : b; ) // Create a node struct Node *newNode(int key) ( struct Node *node = (struct Node *) malloc(sizeof(struct Node)); node->key = key; node->left = NULL; node->right = NULL; node->height = 1; return (node); ) // Right rotate struct Node *rightRotate(struct Node *y) ( struct Node *x = y->left; struct Node *T2 = x->right; x->right = y; y->left = T2; y->height = max(height(y->left), height(y->right)) + 1; x->height = max(height(x->left), height(x->right)) + 1; return x; ) // Left rotate struct Node *leftRotate(struct Node *x) ( struct Node *y = x->right; struct Node *T2 = y->left; y->left = x; x->right = T2; x->height = max(height(x->left), height(x->right)) + 1; y->height = max(height(y->left), height(y->right)) + 1; return y; ) // Get the balance factor int getBalance(struct Node *N) ( if (N == NULL) return 0; return height(N->left) - height(N->right); ) // Insert node struct Node *insertNode(struct Node *node, int key) ( // Find the correct position to insertNode the node and insertNode it if (node == NULL) return (newNode(key)); if (key key) node->left = insertNode(node->left, key); else if (key> node->key) node->right = insertNode(node->right, key); else return node; // Update the balance factor of each node and // Balance the tree node->height = 1 + max(height(node->left), height(node->right)); int balance = getBalance(node); if (balance> 1 && key left->key) return rightRotate(node); if (balance node->right->key) return leftRotate(node); if (balance> 1 && key> node->left->key) ( node->left = leftRotate(node->left); return rightRotate(node); ) if (balance < -1 && key right->key) ( node->right = rightRotate(node->right); return leftRotate(node); ) return node; ) struct Node *minValueNode(struct Node *node) ( struct Node *current = node; while (current->left != NULL) current = current->left; return current; ) // Delete a nodes struct Node *deleteNode(struct Node *root, int key) ( // Find the node and delete it if (root == NULL) return root; if (key key) root->left = deleteNode(root->left, key); else if (key> root->key) root->right = deleteNode(root->right, key); else ( if ((root->left == NULL) || (root->right == NULL)) ( struct Node *temp = root->left ? root->left : root->right; if (temp == NULL) ( temp = root; root = NULL; ) else *root = *temp; free(temp); ) else ( struct Node *temp = minValueNode(root->right); root->key = temp->key; root->right = deleteNode(root->right, temp->key); ) ) if (root == NULL) return root; // Update the balance factor of each node and // balance the tree root->height = 1 + max(height(root->left), height(root->right)); int balance = getBalance(root); if (balance> 1 && getBalance(root->left)>= 0) return rightRotate(root); if (balance> 1 && getBalance(root->left) left = leftRotate(root->left); return rightRotate(root); ) if (balance right) <= 0) return leftRotate(root); if (balance right)> 0) ( root->right = rightRotate(root->right); return leftRotate(root); ) return root; ) // Print the tree void printPreOrder(struct Node *root) ( if (root != NULL) ( printf("%d ", root->key); printPreOrder(root->left); printPreOrder(root->right); ) ) int main() ( struct Node *root = NULL; root = insertNode(root, 2); root = insertNode(root, 1); root = insertNode(root, 7); root = insertNode(root, 4); root = insertNode(root, 5); root = insertNode(root, 3); root = insertNode(root, 8); printPreOrder(root); root = deleteNode(root, 3); printf("After deletion: "); printPreOrder(root); return 0; )
// AVL tree implementation in C++ #include using namespace std; class Node ( public: int key; Node *left; Node *right; int height; ); int max(int a, int b); // Calculate height int height(Node *N) ( if (N == NULL) return 0; return N->height; ) int max(int a, int b) ( return (a> b) ? a : b; ) // New node creation Node *newNode(int key) ( Node *node = new Node(); node->key = key; node->left = NULL; node->right = NULL; node->height = 1; return (node); ) // Rotate right Node *rightRotate(Node *y) ( Node *x = y->left; Node *T2 = x->right; x->right = y; y->left = T2; y->height = max(height(y->left), height(y->right)) + 1; x->height = max(height(x->left), height(x->right)) + 1; return x; ) // Rotate left Node *leftRotate(Node *x) ( Node *y = x->right; Node *T2 = y->left; y->left = x; x->right = T2; x->height = max(height(x->left), height(x->right)) + 1; y->height = max(height(y->left), height(y->right)) + 1; return y; ) // Get the balance factor of each node int getBalanceFactor(Node *N) ( if (N == NULL) return 0; return height(N->left) - height(N->right); ) // Insert a node Node *insertNode(Node *node, int key) ( // Find the correct postion and insert the node if (node == NULL) return (newNode(key)); if (key key) node->left = insertNode(node->left, key); else if (key> node->key) node->right = insertNode(node->right, key); else return node; // Update the balance factor of each node and // balance the tree node->height = 1 + max(height(node->left), height(node->right)); int balanceFactor = getBalanceFactor(node); if (balanceFactor> 1) ( if (key left->key) ( return rightRotate(node); ) else if (key> node->left->key) ( node->left = leftRotate(node->left); return rightRotate(node); ) ) if (balanceFactor node->right->key) ( return leftRotate(node); ) else if (key right->key) ( node->right = rightRotate(node->right); return leftRotate(node); ) ) return node; ) // Node with minimum value Node *nodeWithMimumValue(Node *node) ( Node *current = node; while (current->left != NULL) current = current->left; return current; ) // Delete a node Node *deleteNode(Node *root, int key) ( // Find the node and delete it if (root == NULL) return root; if (key key) root->left = deleteNode(root->left, key); else if (key> root->key) root->right = deleteNode(root->right, key); else ( if ((root->left == NULL) || (root->right == NULL)) ( Node *temp = root->left ? root->left : root->right; if (temp == NULL) ( temp = root; root = NULL; ) else *root = *temp; free(temp); ) else ( Node *temp = nodeWithMimumValue(root->right); root->key = temp->key; root->right = deleteNode(root->right, temp->key); ) ) if (root == NULL) return root; // Update the balance factor of each node and // balance the tree root->height = 1 + max(height(root->left), height(root->right)); int balanceFactor = getBalanceFactor(root); if (balanceFactor> 1) ( if (getBalanceFactor(root->left)>= 0) ( return rightRotate(root); ) else ( root->left = leftRotate(root->left); return rightRotate(root); ) ) if (balanceFactor right) right = rightRotate(root->right); return leftRotate(root); ) ) return root; ) // Print the tree void printTree(Node *root, string indent, bool last) ( if (root != nullptr) ( cout << indent; if (last) ( cout << "R----"; indent += " "; ) else ( cout << "L----"; indent += "| "; ) cout right, indent, true); ) ) int main() ( Node *root = NULL; root = insertNode(root, 33); root = insertNode(root, 13); root = insertNode(root, 53); root = insertNode(root, 9); root = insertNode(root, 21); root = insertNode(root, 61); root = insertNode(root, 8); root = insertNode(root, 11); printTree(root, "", true); root = deleteNode(root, 13); cout << "After deleting " << endl; printTree(root, "", true); )
Складності різних операцій на дереві AVL
Вставка | Видалення | Пошук |
O (журнал n) | O (журнал n) | O (журнал n) |
Програми дерева AVL
- Для індексації великих записів у базах даних
- Для пошуку у великих базах даних