AVL樹是最先發明的自平衡二叉查找樹。在AVL樹中任何節點的兩個兒子子樹的高度最大差別爲一,所以它也被稱爲高度平衡樹。
查找、插入和刪除在平均和最壞情況下都是O(log n)。增加和刪除可能需要通過一次或多次樹旋轉來重新平衡這個樹。
對二叉樹的平衡調整過程,主要包含四種旋轉操作:LL,LR,RR,RL 。
LR由當前節點左兒子的一次RR旋轉和當前節點的一次LL旋轉構成。同理, RR由當前節點右兒子的一次LL旋轉和當前節點的一次RR旋轉構成。
如圖:
AVL樹的 插入 和刪除均要調整重新構成平衡樹。
具體實現代碼即註釋如下:Head.h fun.c AvlTree.c
Head.h
- #ifndef HEAD_H_
- #define HEAD_H_
- #include <stdio.h>
- #include <stdlib.h>
- typedef int ElementType;
- typedef struct AvlNode // AVL樹的節點
- {
- ElementType data;
- struct AvlNode *left; // 左孩子
- struct AvlNode *right; // 右孩子
- int Height;
- }*Position,*AvlTree;
- AvlTree MakeEmpty(AvlTree T);
- Position Find(ElementType x,AvlTree T);
- Position FindMin(AvlTree T);
- Position FindMax(AvlTree T);
- AvlTree Insert(ElementType x,AvlTree T);
- AvlTree Delete(ElementType x,AvlTree T);
- ElementType Retrieve(Position P);
- void Display(AvlTree T);
- #endif /* HEAD_H_ */
fun.c
- #include"Head.h"
- /*
- * 初始化AVL樹
- */
- AvlTree MakeEmpty(AvlTree T)
- {
- if( T != NULL)
- {
- MakeEmpty(T->left);
- MakeEmpty(T->right);
- free(T);
- }
- return NULL;
- }
- /*
- * 查找 可以像普通二叉查找樹一樣的進行,所以耗費O(log n)時間,因爲AVL樹總是保持平衡的。
- * 不需要特殊的準備,樹的結構不會由於查找而改變。(這是與伸展樹查找相對立的,它會因爲查找而變更樹結構。)
- */
- Position Find(ElementType x,AvlTree T)
- {
- if(T == NULL)
- return NULL;
- if(x < T->data)
- return Find(x,T->left);
- else if(x > T->data)
- return Find(x,T->right);
- else
- return T;
- }
- /*
- * FindMax,FindMin 查找最大和最小值,
- */
- Position FindMin(AvlTree T)
- {
- if(T == NULL)
- return NULL;
- if( T->left == NULL)
- return T;
- else
- return FindMin(T->left);
- }
- Position FindMax(AvlTree T)
- {
- if(T != NULL)
- while(T->right != NULL)
- T=T->right;
- return T;
- }
- /*
- * 返回節點的高度
- */
- static int Height(Position P)
- {
- if(P == NULL)
- return -1;
- else
- return P->Height;
- }
- static int Max(int h1,int h2)
- {
- return h1 > h2 ?h1:h2;
- }
- /*
- * 此函數用於k2只有一個左孩子的單旋轉,
- * 在K2和它的左孩子之間旋轉,
- * 更新高度,返回新的根節點
- */
- static Position SingleRotateWithLeft(Position k2) // LL旋轉
- {
- Position k1;
- k1=k2->left;
- k2->left=k1->right;
- k1->right=k2;
- // 因爲比較的是左右孩子的高度,所以求父節點的高度要加1
- k2->Height=Max(Height(k2->left),Height(k2->right)) + 1;
- k1->Height=Max(Height(k1->left),Height(k2->right)) + 1;
- return k1;
- }
- /*
- * 此函數用於k1只有一個右孩子的單旋轉,
- * 在K1和它的右孩子之間旋轉,
- * 更新高度,返回新的根節點
- */
- static Position SingleRotateWithRight(Position k1) // RR旋轉
- {
- Position k2;
- k2=k1->right;
- k1->right=k2->left;
- k2->left=k1;
- /*結點的位置變了, 要更新結點的高度值*/
- k1->Height=Max(Height(k1->left),Height(k1->right)) + 1;
- k2->Height=Max(Height(k2->left),Height(k2->right)) + 1;
- return k2;
- }
- /*
- * 此函數用於當 如果 k3有一個左孩子,以及
- * 它的左孩子又有右孩子,執行這個雙旋轉
- * 更新高度,返回新的根節點
- */
- static Position DoubleRotateLeft(Position k3) // LR旋轉
- {
- //在 k3 的左孩子,執行右側單旋轉
- k3->left=SingleRotateWithRight(k3->left);
- // 再對 k3 進行 左側單旋轉
- return SingleRotateWithLeft(k3);
- }
- /*
- * 此函數用於當 如果 k4有一個右孩子,以及
- * 它的右孩子又有左孩子,執行這個雙旋轉
- * 更新高度,返回新的根節點
- */
- static Position DoubleRotateRight(Position k4) // RL旋轉
- {
- //在 k4 的右孩子,執行左側單旋轉
- k4->right = SingleRotateWithLeft(k4->right);
- // 再對 k4 進行 右側單旋轉
- return SingleRotateWithRight(k4);
- }
- /*
- * 向AVL樹插入可以通過如同它是未平衡的二叉查找樹一樣把給定的值插入樹中,
- * 接着自底向上向根節點折回,於在插入期間成爲不平衡的所有節點上進行旋轉來完成。
- * 因爲折回到根節點的路途上最多有1.5乘log n個節點,而每次AVL旋轉都耗費恆定的時間,
- * 插入處理在整體上耗費O(log n) 時間。
- */
- AvlTree Insert(ElementType x,AvlTree T)
- {
- //如果T不存在,則創建一個節點樹
- if(T == NULL)
- {
- T = (AvlTree)malloc(sizeof(struct AvlNode));
- {
- T->data = x;
- T->Height = 0;
- T->left = T->right = NULL;
- }
- }
- // 如果要插入的元素小於當前元素
- else if(x < T->data)
- {
- //遞歸插入
- T->left=Insert(x,T->left);
- //插入元素之後,若 T 的左子樹比右子樹高度 之差是 2,即不滿足 AVL平衡特性,需要調整
- if(Height(T->left) - Height(T->right) == 2)
- {
- //把x插入到了T->left的左側,只需 左側單旋轉
- if(x < T->left->data)
- T = SingleRotateWithLeft(T); // LL旋轉
- else
- // x 插入到了T->left的右側,需要左側雙旋轉
- T = DoubleRotateLeft(T); // LR旋轉
- }
- }
- // 如果要插入的元素大於當前元素
- else if(x > T->data)
- {
- T->right=Insert(x,T->right);
- if(Height(T->right) - Height(T->left) == 2)
- {
- if(x > T->right->data)
- T = SingleRotateWithRight(T); //RR 旋轉
- else
- T = DoubleRotateRight(T); //RL旋轉
- }
- }
- T->Height=Max(Height(T->left),Height(T->right)) + 1;
- return T;
- }
- /*
- * 對單個節點進行的AVL調整
- */
- AvlTree Rotate(AvlTree T)
- {
- if(Height(T->left) - Height(T->right) == 2)
- {
- if(Height(T->left->left) >= Height(T->left->right))
- T = SingleRotateWithLeft(T); // LL旋轉
- else
- T = DoubleRotateLeft(T); // LR旋轉
- }
- if(Height(T->right) - Height(T->left) == 2)
- {
- if(Height(T->right->right) >= Height(T->right->left))
- T = SingleRotateWithRight(T); // RR旋轉
- else
- T = DoubleRotateRight(T); // RL旋轉
- }
- return T;
- }
- /*
- * 首先定位要刪除的節點,然後用該節點的右孩子的最左孩子替換該節點,
- * 並重新調整以該節點爲根的子樹爲AVL樹,具體調整方法跟插入數據類似
- * 刪除處理在整體上耗費O(log n) 時間。
- */
- AvlTree Delete(ElementType x,AvlTree T)
- {
- if(T == NULL)
- return NULL;
- if(T->data == x) // 要刪除的 x 等於當前節點元素
- {
- if(T->right == NULL ) // 若所要刪除的節點 T 的右孩子爲空,則直接刪除
- {
- AvlTree tmp = T;
- T = T->left;
- free(tmp);
- }
- else /* 否則找到 T->right 的最左兒子代替 T */
- {
- AvlTree tmp = T->right;
- while(tmp->left)
- tmp=tmp->left;
- T->data = tmp->data;
- /* 對於替代後的T 即其字節點進行調整*/
- T->right = Delete(T->data,T->right);
- T->Height = Max(Height(T->left),Height(T->right))+1;
- }
- return T;
- }
- else if(x > T->data) // 要刪除的 x 大於當前節點元素,在T的右子樹中查找刪除
- {
- T->right=Delete(x,T->right);
- }
- else // 要刪除的 x 小於當前節點元素,在T的左子樹中查找刪除
- {
- T->left=Delete(x,T->left);
- }
- /*
- * 當刪除元素後調整平衡
- */
- T->Height=Max(Height(T->left),Height(T->right)) + 1;
- if(T->left != NULL)
- T->left = Rotate(T->left);
- if(T->right != NULL)
- T->right = Rotate(T->right);
- if(T)
- T=Rotate(T);
- return T;
- }
- /*
- * 返回當前位置的元素
- */
- ElementType Retrieve(Position P)
- {
- return P->data;
- }
- /*
- * 遍歷輸出
- */
- void Display(AvlTree T)
- {
- static int n=0;
- if(NULL != T)
- {
- Display(T->left);
- printf("[%d] ndata=%d \n",++n,T->data);
- Display(T->right);
- }
- }
AvlTree.c
- #include"Head.h"
- #define N 15
- int main(void) {
- AvlTree T=NULL;
- int i;
- int j = 0;
- T = MakeEmpty( NULL );
- for( i = 0; i < N; i++, j = ( j + 7 ) % 50 )
- {
- printf("j=%d \n",j);
- T = Insert( j, T );
- }
- puts("插入 4 \n");
- T = Insert( 4, T );
- Display(T);
- for( i = 0; i < N; i += 2 )
- {
- printf("delelte: %d \n",i);
- T = Delete( i, T );
- }
- printf("detele:\n");
- printf("height=%d \n",T->Height);
- Display(T);
- printf( "Min is %d, Max is %d\n", Retrieve( FindMin( T ) ),
- Retrieve( FindMax( T ) ) );
- return EXIT_SUCCESS;
- }