????????AVL樹是一種自平衡的二叉搜索樹,得名于其發明者G.M. Adelson-Velsky和E.M. Landis。在AVL樹中,任何節點的兩個子樹的高度最多相差1,這種性質確保了AVL樹的查找、插入和刪除操作的時間復雜度接近O(log n)。
????????AVL樹是一種二叉搜索樹,它通過調整節點間的結構來保持樹的平衡。平衡因子(Balance Factor)是AVL樹中一個關鍵的概念,定義為節點的左子樹高度與右子樹高度的差。在AVL樹中,任何節點的平衡因子的絕對值不得超過1。如下圖所示。
?????????AVL樹通過旋轉操作來保持樹的平衡,AVL樹在節點插入或刪除后,若導致樹不平衡,則會通過四種旋轉操作之一來重新平衡樹。這四種旋轉操作分別是:左旋、右旋、左右旋和右左旋。
????????1.?左旋操作通常發生在右子樹比左子樹高太多的時候。具體操作是:將當前節點(我們稱其為T)的右子節點(我們稱其為R)提升為新的根節點,將T節點降為R的左子節點,R的左子節點則成為T的右子節點。示例代碼如下。
struct TreeNode {int val;int height;TreeNode* left;TreeNode* right;TreeNode(int val) : val(val), height(1), left(nullptr), right(nullptr) {}
};TreeNode* leftRotate(TreeNode* x) {TreeNode* y = x->right; // y是x的右子節點x->right = y->left; // y的左子節點成為x的右子節點y->left = x; // x成為y的左子節點// 更新高度x->height = 1 + max(height(x->left), height(x->right));y->height = 1 + max(height(y->left), height(y->right));return y; // 新的根節點
}
? ? ? ? 2. 右旋操作與左旋相反,發生在節點不平衡,且平衡因子小于-1,同時左子節點的平衡因子小于等于0時。我們將左子節點提升為當前節點的父節點,當前節點變為左子節點的右子節點,完成右旋。示例代碼如下。
TreeNode* rightRotate(TreeNode* y) {TreeNode* x = y->left; // x是y的左子節點y->left = x->right; // x的右子節點成為y的左子節點x->right = y; // y成為x的右子節點// 更新高度x->height = 1 + max(height(x->left), height(x->right));y->height = 1 + max(height(y->left), height(y->right));return x; // 新的根節點
}
?????????3.?左右旋是左旋和右旋的組合操作,發生在節點不平衡,且平衡因子大于1,同時右子節點的平衡因子小于0時。首先,對右子節點進行左旋,然后對整個樹以當前節點為根進行右旋。
? ? ? ? 4.?右左旋也是左旋和右旋的組合操作,但順序相反。它發生在節點不平衡,且平衡因子小于-1,同時左子節點的平衡因子大于0時。首先,對左子節點進行右旋,然后對整個樹以當前節點為根進行左旋。?
????????在實際應用中,當我們對AVL樹進行插入或刪除操作時,一旦導致樹不平衡,我們就需要根據節點及其子節點的平衡因子,決定執行哪種旋轉操作,來恢復樹的平衡。通過正確應用這四種旋轉操作,我們可以確保AVL樹始終保持平衡狀態,從而保持高效的性能。
????????需要注意的是,旋轉操作只是AVL樹維護平衡的一種方式,實際的應用場景中還需要處理其他情況,比如如何高效地查找節點、如何正確地插入和刪除節點等。但無論何種情況,保持樹的平衡都是AVL樹設計的核心所在。
????????AVL樹由于具有良好的平衡性,常被用于需要高效查找、插入和刪除操作的場景中,如數據緩存、關聯數組、文件系統等。它提供了一種高效的存儲和訪問數據的方式,特別是在數據量大、操作頻繁的情況下,AVL樹能夠保持較好的性能。
????????下面是一個簡單的AVL樹的C++實現,包含插入、刪除和打印樹的函數。代碼如下。
#include <iostream>
#include <stack>
#include <algorithm>
using namespace std;// 定義AVL樹的節點結構體
struct AVLNode {int key;int height;AVLNode* left;AVLNode* right;AVLNode(int k) : key(k), height(1), left(nullptr), right(nullptr) {}
};// 查找樹中的最小值節點
AVLNode* minValueNode(AVLNode* node) {AVLNode* current = node;// 循環直到左孩子是nullptrwhile (current->left != nullptr)current = current->left;return current;
}// 獲取節點的高度
int getHeight(AVLNode* N) {if (N == nullptr)return 0;return N->height;
}// 獲取平衡因子
int getBalance(AVLNode* N) {if (N == nullptr)return 0;return getHeight(N->left) - getHeight(N->right);
}// 更新節點高度
void updateHeight(AVLNode* N) {if (N != nullptr)N->height = 1 + max(getHeight(N->left), getHeight(N->right));
}// 右旋
AVLNode* rightRotate(AVLNode* y) {AVLNode* x = y->left;AVLNode* T2 = x->right;x->right = y;y->left = T2;updateHeight(y);updateHeight(x);return x;
}// 左旋
AVLNode* leftRotate(AVLNode* x) {AVLNode* y = x->right;AVLNode* T2 = y->left;y->left = x;x->right = T2;updateHeight(x);updateHeight(y);return y;
}// 獲取插入新節點后的平衡AVL樹
AVLNode* insert(AVLNode* node, int key) {if (node == nullptr)return (new AVLNode(key));if (key < node->key)node->left = insert(node->left, key);else if (key > node->key)node->right = insert(node->right, key);else // Duplicate keys not allowedreturn node;// 更新高度updateHeight(node);// 獲取平衡因子int balance = getBalance(node);// 左左情況if (balance > 1 && key < node->left->key)return rightRotate(node);// 右右情況if (balance < -1 && key > 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 < node->right->key) {node->right = rightRotate(node->right);return leftRotate(node);}return node;
}// 從AVL樹中刪除一個節點
AVLNode* deleteNode(AVLNode* root, int key) {if (root == nullptr)return root;if (key < root->key)root->left = deleteNode(root->left, key);else if (key > root->key)root->right = deleteNode(root->right, key);else {// 節點有兩個子節點if (root->left && root->right) {AVLNode* temp = minValueNode(root->right);root->key = temp->key;root->right = deleteNode(root->right, temp->key);}// 節點只有一個子節點或沒有子節點else {AVLNode* temp = root->left ? root->left : root->right;if (temp == nullptr) {temp = root;root= nullptr;} else {*root = *temp;}free(temp);}}if (root == nullptr)return root;// 更新高度updateHeight(root);// 獲取平衡因子int balance = getBalance(root);// 右右情況if (balance > 1 && getBalance(root->left) >= 0)return rightRotate(root);// 左左情況if (balance < -1 && getBalance(root->right) <= 0)return leftRotate(root);// 左右情況if (balance > 1 && getBalance(root->left) < 0) {root->left = leftRotate(root->left);return rightRotate(root);}// 右左情況if (balance < -1 && getBalance(root->right) > 0) {root->right = rightRotate(root->right);return leftRotate(root);}return root;
}// 打印AVL樹(中序遍歷)
void inorder(AVLNode* root) {if (root != nullptr) {inorder(root->left);cout << root->key << " ";inorder(root->right);}
}// 主函數測試
int main() {AVLNode* root = nullptr;// 插入節點root = insert(root, 10);insert(root, 20);insert(root, 30);insert(root, 40);insert(root, 50);insert(root, 25);// 打印AVL樹cout << "所構建的AVL樹的中序遍歷是 \n";inorder(root);cout << endl;// 刪除節點root = deleteNode(root, 25);// 再次打印AVL樹cout << "刪除后修改的AVL樹的中序遍歷為 \n";inorder(root);cout << endl;return 0;
}
????????總的來說,AVL樹是一種非常有用的數據結構,它通過自動平衡保證了高效的查找、插入和刪除操作。掌握AVL樹的原理和操作對于理解數據結構和算法的重要性以及提高編程技能都非常有幫助。