AVL樹的建立解析含程式碼(C++)
阿新 • • 發佈:2021-12-31
AVL樹
AVL樹是平衡二叉樹,它可以儘可能建立“枝繁葉茂”的樹,防止樹枝過長過少。二叉樹搜尋中,會引入ASL平均查詢長度的概念,表示查詢所有節點的比較次數平均值。平衡二叉樹的ASL相較而言較小。
思路
AVL樹就是比較各個節點左右子樹的深度差,當差值等於2時就需要對樹結構進行改變。改變的方式有左旋、右旋、左右旋以及右左旋。判斷旋轉方式是看導致深度差值的結點在哪。左旋是順時針旋轉相關結點,右旋為逆時針旋轉相關結點。左右旋及右左旋為左旋、右旋的組合,左右旋先右旋後左旋。
如下面圖的示例:
以上圖片來自陳越《資料結構》一書。
關於旋轉結點的程式碼不是很難,RL旋和LR旋為各是兩個單旋的組合,L旋和R旋的思路又都一樣。因此只要搞懂一個方向的單旋即可。注意單旋時旋轉結點的子結點位置的改變。具體的看程式碼。
程式碼
#include <iostream> using namespace std; /*avl平衡樹的建立,需要判斷一個節點左右兩子樹的深度差,差值小於2視為平衡*/ typedef struct node{ int data; node* lchild; node* rchild; int height; }*bitTree; int max(int a,int b) {//用於比較子樹大小 return a>b?a:b; } int getHeight(bitTree T) {//獲取樹的高度 int lnum,rnum,count; if(T){ lnum = getHeight(T->lchild); rnum = getHeight(T->rchild); count = lnum>rnum?lnum:rnum;//比較左右子樹的高度取最大值 return (count+1); } } bitTree singleleftRotation(bitTree T)//左旋 { bitTree B = new node; B = T->lchild; T->lchild = B->rchild; B->rchild = T; T->height = max(getHeight(T->lchild),getHeight(T->rchild))+1; B->height = max(getHeight(B->lchild),T->height)+1; return B; } bitTree singlerightRotation(bitTree T) { bitTree B = T->rchild; T->rchild = B->lchild; B->lchild = T; T->height = max(getHeight(T->lchild),getHeight(T->rchild))+1; B->height = max(getHeight(B->rchild),T->height)+1; } bitTree doubleleftrightRotation(bitTree T) { T->lchild = singlerightRotation(T->lchild); return singleleftRotation(T); } bitTree doublerightleftRotation(bitTree T) { T->rchild = singleleftRotation(T->lchild); return singlerightRotation(T); } bitTree insert(bitTree &T,int x) {//AVL樹在插入的過程中不斷判斷 if(!T)//插入一個空樹 { T = new node; T->data = x; T->lchild = T->rchild = NULL; T->height = 1;//這裡樹高的初值不重要,後續的高度都會做左右子樹高度對比重新取值 } else if(x<T->data){//插入值在左子樹中 T->lchild = insert(T->lchild,x); //對旋的判斷就是看其插入的位置 if(getHeight(T->lchild)-getHeight(T->rchild)==2){ if(x<T->lchild->data)//需要L旋 T = singleleftRotation(T); else//左右旋 T = doubleleftrightRotation(T); } } else if(x>T->data){//插入值在右子樹中 T->rchild = insert(T->rchild,x); //對旋的判斷就是看其插入的位置 if(getHeight(T->lchild)-getHeight(T->rchild)==2){ if(x>T->rchild->data)//需要R旋 T = singlerightRotation(T); else//RL旋 T = doublerightleftRotation(T); } } T->height = max(getHeight(T->lchild),getHeight(T->rchild))+1;//插入了新值,樹的高度加一 return T; } int display(bitTree T) {//先序遍歷 if(T!=NULL) { display(T->lchild); cout<<T->data<<" "; display(T->rchild); } } int main() { /* 示例生成二叉樹: 18 / \ 10 20 / \ / \ 9 11 19 22 */ bitTree T; int a[7] = {9,11,19,22,18,10,20}; for(int i = 0;i<7;i++) insert(T,a[i]); display(T); //輸出9 10 11 18 19 20 22 }
注意點
結點的單旋需要傳入的結點為第一個深度不平衡的結點。多旋則是先對不平衡結點的下一個子節點單旋,後對不平衡結點再做一次單旋。
下面以RL旋做一個例子