AVL 樹是最早發明的自平衡二叉搜索樹,通過維護節點平衡因子(左右子樹高度差)在 {-1,0,1} 範圍內,保證查找、插入、刪除均為 O(log n)。本文深入講解四種旋轉操作及插入再平衡邏輯,提供完整 C 代碼。
typedef struct AvlNode *Position;
typedef struct AvlNode *AvlTree;
struct AvlNode {
int Element;
AvlTree Left;
AvlTree Right;
int Height; // 節點高度,葉子為 0,空為 -1
};
static int HeightAvl(Position P) {
return (P == NULL) ? -1 : P->Height;
}
static int Max(int a, int b) { return (a > b) ? a : b; }
旋轉本質是局部重構,在保持中序遍歷序列不變的前提下降低樹高。
情況:節點 K2 的左子樹左側過高(插入在 K2->Left->Left)。
static Position SingleRotateWithLeft(Position K2) {
Position K1 = K2->Left;
K2->Left = K1->Right;
K1->Right = K2;
// 更新高度:先更新原根 K2,再更新新根 K1
K2->Height = Max(HeightAvl(K2->Left), HeightAvl(K2->Right)) + 1;
K1->Height = Max(HeightAvl(K1->Left), HeightAvl(K1->Right)) + 1; // 注意此處應為 K1->Right 即 K2
return K1; // 新根
}
鏡像對稱,插入在 K2->Right->Right。
static Position SingleRotateWithRight(Position K2) {
Position K1 = K2->Right;
K2->Right = K1->Left;
K1->Left = K2;
K2->Height = Max(HeightAvl(K2->Left), HeightAvl(K2->Right)) + 1;
K1->Height = Max(HeightAvl(K1->Left), HeightAvl(K1->Right)) + 1;
return K1;
}
情況:插入在 K3->Left->Right。先對左孩子右單旋,再對 K3 左單旋。
static Position DoubleRotateWithLeft(Position K3) {
K3->Left = SingleRotateWithRight(K3->Left); // 變為 LL 型
return SingleRotateWithLeft(K3);
}
鏡像對稱:插入在 K3->Right->Left。先對右孩子左單旋,再對 K3 右單旋。
static Position DoubleRotateWithRight(Position K3) {
K3->Right = SingleRotateWithLeft(K3->Right); // 變為 RR 型
return SingleRotateWithRight(K3);
}
AvlTree InsertAvl(int X, AvlTree T) {
if (T == NULL) {
T = malloc(sizeof(struct AvlNode));
if (T == NULL) { fprintf(stderr, "Out of space\\n"); exit(1); }
T->Element = X; T->Height = 0; T->Left = T->Right = NULL;
} else if (X < T->Element) {
T->Left = InsertAvl(X, T->Left);
// 檢查左側失衡
if (HeightAvl(T->Left) - HeightAvl(T->Right) == 2) {
if (X < T->Left->Element) // LL
T = SingleRotateWithLeft(T);
else // LR
T = DoubleRotateWithLeft(T);
}
} else if (X > T->Element) {
T->Right = InsertAvl(X, T->Right);
// 檢查右側失衡
if (HeightAvl(T->Right) - HeightAvl(T->Left) == 2) {
if (X > T->Right->Element) // RR
T = SingleRotateWithRight(T);
else // RL
T = DoubleRotateWithRight(T);
}
}
// 相等不插入
T->Height = Max(HeightAvl(T->Left), HeightAvl(T->Right)) + 1;
return T;
}
int main(void) {
AvlTree Tree = NULL;
int nums[] = {10, 20, 30, 40, 50, 25}; // 觸發 RR, LR 等旋轉
for (int i = 0; i < 6; i++) Tree = InsertAvl(nums[i], Tree);
// 中序遍歷應有序:10 20 25 30 40 50
// 可添加打印函數驗證樹高平衡
return 0;
}
AVL 樹通過嚴格平衡條件提供極佳查找性能,但插入/刪除需多次旋轉,實際工程中紅黑樹(RB-Tree)因鬆弛平衡條件、旋轉次數少,更常用於標準庫實現(如 C++ `std::map`、Linux 內核 `rb_tree`)。理解 AVL 旋轉機制是掌握所有平衡樹的基石。