Cây AVL: Xoay, chèn, xóa bằng C++ Ví dụ
⚡ Tóm tắt thông minh
AVL Trees are self-balancing binary search trees where the height difference between the left and right subtrees of every node stays within -1, 0, or +1, guaranteeing O(log n) search performance.

Cây AVL là gì?
Cây AVL are binary search trees in which the height difference between the left and right subtree of every node is -1, 0, or +1. They are self-balancing BSTs that maintain logarithmic search time, named after inventors Adelson-Velsky and Landis (AVL).
Cây AVL hoạt động như thế nào?
To understand why AVL Trees exist, look at what goes wrong with a plain Cây tìm kiếm nhị phân. Consider these keys inserted in the given order:
Trực quan hóa cây AVL
The tree grows linearly when keys arrive in increasing order, degenerating search to O(n). That defeats the purpose of a BST — only a balanced tree keeps search logarithmic. Now look at the same keys inserted in a different order.
Same keys, different insertion order produces a shallower shape, so every search runs in O(log n). AVL Trees enforce that shape by watching the height on every insertion and correcting imbalance without breaking BST ordering.
Hệ số cân bằng trong cây AVL
The balance factor (BF) tracks each node’s height so the tree can self-balance on the fly.
Thuộc tính của yếu tố cân bằng
Cây AVL hệ số cân bằng
- The balance factor is the difference between the height of the left subtree and the height of the right subtree.
Balance factor(node) = height(node->left) − height(node->right)- The only allowed values are −1, 0, and +1.
- A value of −1 means the right subtree contains one extra level — the node is right-heavy.
- A value of +1 means the left subtree contains one extra level — the node is left-heavy.
- A value of 0 means both sides have equal height — the node is perfectly balanced.
Xoay AVL
Rotations run whenever an insertion or deletion breaks the balance factor rule. The four cases are LL, RR, LR, and RL.
Xoay trái – Xoay trái
Việc xoay này được thực hiện khi một nút mới được chèn vào nút con bên trái của cây con bên trái.
Cây AVL Trái – Xoay Trái
A single right rotation is performed. This case fires when a node has BF +2 and its left child has BF +1.
Phải – Xoay Phải
Việc xoay này được thực hiện khi một nút mới được chèn vào con bên phải của cây con bên phải.
A single left rotation is performed. This case fires when a node has BF −2 and its right child has BF −1.
Xoay phải – trái
Việc xoay này được thực hiện khi một nút mới được chèn vào con trái của cây con bên phải.
Fires when BF(node) = −2 and BF(right-child) = +1. Right-rotate the right child, then left-rotate the node.
Xoay Trái – Phải
Việc xoay này được thực hiện khi một nút mới được chèn vào nút con bên phải của cây con bên trái.
Fires when BF(node) = +2 and BF(left-child) = −1. Left-rotate the left child, then right-rotate the node.
Chèn vào cây AVL
Insertion is almost identical to a plain BST insert. After every insert, the tree walks up and re-balances. Insert runs in O(log n) worst-case time.
Triển khai chèn cây AVL
Bước 1: Insert the node using the standard BST algorithm. In the example above, insert 160.
Bước 2: Update the balance factor of every ancestor along the insertion path.
Bước 3: If any ancestor violates the balance factor range, perform the matching rotation. In the example, node 350’s balance factor is violated, so an LL rotation restores balance.
- If
BF(node) = +2vàBF(left-child) = +1, perform LL rotation. - If
BF(node) = −2vàBF(right-child) = −1, perform RR rotation. - If
BF(node) = −2vàBF(right-child) = +1, perform RL rotation. - If
BF(node) = +2vàBF(left-child) = −1, perform LR rotation.
Xóa trong cây AVL
Deletion follows the same logic as a plain BST and re-balances afterwards.
Bước 1: Tìm phần tử trong cây.
Bước 2: Delete the node using standard BST deletion.
Bước 3: Two cases are possible.
Trường hợp 1: Xóa từ cây con bên phải.
- 1A. If
BF(node) = +2vàBF(left-child) = +1, perform LL rotation. - Năm 1B. If
BF(node) = +2vàBF(left-child) = −1, perform LR rotation. - 1C. If
BF(node) = +2vàBF(left-child) = 0, perform LL rotation.
Trường hợp 2: Deleting from the left subtree.
- 2A. If
BF(node) = −2vàBF(right-child) = −1, perform RR rotation. - Năm 2B. If
BF(node) = −2vàBF(right-child) = +1, perform RL rotation. - 2C. If
BF(node) = −2vàBF(right-child) = 0, perform RR rotation.
C++ Ví dụ về cây AVL
Dưới đây là một C++ program implementing AVL Trees:
#include <iostream> #include <queue> #include <unordered_map> using namespace std; struct node { struct node *left; int data; int height; struct node *right; }; class AVL { public: struct node *root; AVL() { this->root = NULL; } int calheight(struct node *p) { if (p->left && p->right) { if (p->left->height < p->right->height) return p->right->height + 1; else return p->left->height + 1; } else if (p->left && p->right == NULL) { return p->left->height + 1; } else if (p->left == NULL && p->right) { return p->right->height + 1; } return 0; } int bf(struct node *n) { if (n->left && n->right) return n->left->height - n->right->height; else if (n->left && n->right == NULL) return n->left->height; else if (n->left == NULL && n->right) return -n->right->height; return 0; } struct node *llrotation(struct node *n) { struct node *p = n; struct node *tp = p->left; p->left = tp->right; tp->right = p; return tp; } struct node *rrrotation(struct node *n) { struct node *p = n; struct node *tp = p->right; p->right = tp->left; tp->left = p; return tp; } struct node *rlrotation(struct node *n) { struct node *p = n; struct node *tp = p->right; struct node *tp2 = p->right->left; p->right = tp2->left; tp->left = tp2->right; tp2->left = p; tp2->right = tp; return tp2; } struct node *lrrotation(struct node *n) { struct node *p = n; struct node *tp = p->left; struct node *tp2 = p->left->right; p->left = tp2->right; tp->right = tp2->left; tp2->right = p; tp2->left = tp; return tp2; } struct node *insert(struct node *r, int data) { if (r == NULL) { r = new struct node; r->data = data; r->left = r->right = NULL; r->height = 1; return r; } if (data < r->data) r->left = insert(r->left, data); else r->right = insert(r->right, data); r->height = calheight(r); if (bf(r) == 2 && bf(r->left) == 1) r = llrotation(r); else if (bf(r) == -2 && bf(r->right) == -1) r = rrrotation(r); else if (bf(r) == -2 && bf(r->right) == 1) r = rlrotation(r); else if (bf(r) == 2 && bf(r->left) == -1) r = lrrotation(r); return r; } void levelorder_newline() { if (this->root == NULL) { cout << "\nEmpty tree\n"; return; } levelorder_newline(this->root); } void levelorder_newline(struct node *v) { queue<struct node *> q; struct node *cur; q.push(v); q.push(NULL); while (!q.empty()) { cur = q.front(); q.pop(); if (cur == NULL && q.size() != 0) { cout << "\n"; q.push(NULL); continue; } if (cur != NULL) { cout << " " << cur->data; if (cur->left != NULL) q.push(cur->left); if (cur->right != NULL) q.push(cur->right); } } } struct node *deleteNode(struct node *p, int data) { if (p->left == NULL && p->right == NULL) { if (p == this->root) this->root = NULL; delete p; return NULL; } struct node *q; if (p->data < data) p->right = deleteNode(p->right, data); else if (p->data > data) p->left = deleteNode(p->left, data); else { if (p->left != NULL) { q = inpre(p->left); p->data = q->data; p->left = deleteNode(p->left, q->data); } else { q = insuc(p->right); p->data = q->data; p->right = deleteNode(p->right, q->data); } } if (bf(p) == 2 && bf(p->left) == 1) p = llrotation(p); else if (bf(p) == 2 && bf(p->left) == -1) p = lrrotation(p); else if (bf(p) == 2 && bf(p->left) == 0) p = llrotation(p); else if (bf(p) == -2 && bf(p->right) == -1) p = rrrotation(p); else if (bf(p) == -2 && bf(p->right) == 1) p = rlrotation(p); else if (bf(p) == -2 && bf(p->right) == 0) p = rrrotation(p); return p; } struct node *inpre(struct node *p) { while (p->right != NULL) p = p->right; return p; } struct node *insuc(struct node *p) { while (p->left != NULL) p = p->left; return p; } ~AVL() {} }; int main() { AVL b; int c, x; do { cout << "\n1.Display levelorder on newline"; cout << "\n2.Insert"; cout << "\n3.Delete\n"; cout << "\n0.Exit\n"; cout << "\nChoice: "; cin >> c; switch (c) { case 1: b.levelorder_newline(); break; case 2: cout << "\nEnter no. "; cin >> x; b.root = b.insert(b.root, x); break; case 3: cout << "\nWhat to delete? "; cin >> x; b.root = b.deleteNode(b.root, x); break; case 0: break; } } while (c != 0); }
Running example of the code above:
- Copy the code above and save it in a file named
avl.cpp. - Biên dịch mã:
g++ avl.cpp -o run
- Chạy mã.
./run
Ưu điểm của cây AVL
- The height of the AVL Tree is always balanced and never grows beyond log N.
- Search is faster than a plain Binary Search Tree because the tree cannot degenerate.
- Self-balancing is automatic — no rebuild step is required.
- Deterministic performance suits real-time systems and in-memory indexes.











