1. 程式人生 > 實用技巧 >AVL樹

AVL樹

//bf=右子樹-左子樹,刪除時用左子樹的中序最後一個結點填充
#include<iostream>
#include<stack>
#include<queue>
using namespace std;

struct Node{
    int bf;
    int data;
    Node* left;
    Node* right;
    Node():bf(0),left(NULL),right(NULL){}
};
void RR(Node* &ptr){  //左單旋轉
    Node* subL=ptr;
    ptr=ptr->right;
    subL
->right=ptr->left; ptr->left=subL; ptr->bf=subL->bf=0; } void LL(Node* &ptr){ //右單旋轉 Node* subR=ptr; ptr=ptr->left; subR->left=ptr->right; ptr->right=subR; ptr->bf=subR->bf=0; } void LR(Node* &ptr){ //先左後右雙旋轉 Node *subR=ptr, *subL=ptr->left; ptr
=ptr->left->right; subL->right=ptr->left; ptr->left=subL; if(ptr->bf==-1||ptr->bf==0) subL->bf=0; //ptr->bf值可能為-1或0 else subL->bf=-1; subR->left=ptr->right; ptr->right=subR; if(ptr->bf==-1) subR->bf=1; else subR->bf=0; ptr
->bf=0; } void RL(Node* &ptr){ //先右後左雙旋轉 Node *subL=ptr,*subR=ptr->right; ptr=ptr->right->left; subR->left=ptr->right; ptr->right=subR; if(ptr->bf==1||ptr->bf==0) subR->bf=0; //ptr->bf值可能為1或0 else subR->bf=1; subL->right=ptr->left; ptr->left=subL; if(ptr->bf==1) subL->bf=-1; else subL->bf=0; ptr->bf=0; } bool Insert(Node* &ptr,int el){ Node *pre=NULL, *p=ptr, *ppre; //ptr指標記錄根節點 stack<Node*> st; while(p!=NULL){ if(el==p->data) return false; pre=p; st.push(pre); if(el<p->data) p=p->left; else p=p->right; } p=new Node(); p->data=el; if(pre==NULL){ ptr=p; return true; } if(el<pre->data) pre->left=p; else pre->right=p; while(!st.empty()){ pre=st.top(); st.pop(); if(p==pre->left) pre->bf--; //平衡因子的更新 else pre->bf++; //平衡因子的更新 if(pre->bf==0) break; if(pre->bf==1||pre->bf==-1) p=pre; else{ if(pre->bf*p->bf>0){ //同號,單旋轉 if(pre->bf==-2) LL(pre); else RR(pre); }else{ //異號,雙旋轉 if(pre->bf==-2) LR(pre); else RL(pre); } break; } } if(st.empty()){ ptr=pre; }else{ ppre=st.top(); if(pre->data<ppre->data) ppre->left=pre; else ppre->right=pre; } return true; } bool Remove(Node* &ptr,int x) { Node *pre=NULL, *p=ptr, *temp, *ppre; stack<Node*> st; while(p!=NULL) //尋找刪除位置 { if(x==p->data) break; //找到等於x的結點p,停止搜尋 pre=p; st.push(pre); //否則用棧記憶查詢路徑 if(x<p->data) p=p->left; else p=p->right; } if(p==NULL) return false; //未找到被刪除結點,刪除失敗 if(p->left!=NULL&&p->right!=NULL) //被刪除結點有兩個子女 { pre=p; st.push(pre); temp=p->left; //在p左子樹找p的直接前驅 while(temp->right!=NULL) { pre=temp; st.push(pre); temp=temp->right; } p->data=temp->data; //用temp的值填補p p=temp; //被刪結點轉化為temp,使p指向temp } if(p->left!=NULL) temp=p->left; //被刪結點p只有一個子女q else temp=p->right; if(pre==NULL) ptr=temp; //被刪結點為根節點,當真正刪除的結點為根結點時,那表明這個樹就這一個結點,ptr=NULL else //被刪結點不是根結點 { if(pre->left==p) pre->left=temp; //連線,此後temp完成刪除後子女連結的使命 else pre->right=temp; while(!st.empty()) //重新平衡化 { pre=st.top(); st.pop(); //從棧中退出父結點 if(pre->right==temp) pre->bf--; //調整父結點的平衡因子 else pre->bf++; if(pre->bf==0) temp=pre; // |bf|=0 if(pre->bf==1||pre->bf==-1) break; // |bf|=1 if(pre->bf==2||pre->bf==-2) // |bf|=2 { if(pre->bf=-2) temp=pre->left; //用temp指向較高的子樹 else temp=pre->right; //用temp指向較高的子樹 if(temp->bf==0) { if(pre->bf=-2) { LL(pre); //右單旋轉,但把pre->bf=pre->left->bf=0了,下面需要值重置 pre->bf=1; pre->left->bf=-1; } else { RR(pre); //左單旋轉,但把pre->bf=pre->left->bf=0了,下面需要值重置 pre->bf=-1; pre->right->bf=1; } break; } if(temp->bf * pre->bf > 0) //兩結點平衡因子同號 { if(pre->bf==-2) LL(pre); //右單旋轉 else RR(pre); //左單旋轉 } else //兩結點平衡因子反號 { if(pre->bf==-2) LR(pre); //先左後右雙旋轉, " < "型 else RL(pre); //先右後左雙旋轉," > "型 } } } if(st.empty()) { //旋轉後與上層連結 ptr=pre; }else{ ppre=st.top(); if(pre->data<ppre->data) ppre->left=pre; else ppre->right=pre; } } delete p; return true; } void LevelTraversal(Node* ptr){ queue<Node*> Q; Node* p=NULL; Q.push(ptr); while(!Q.empty()){ p=Q.front(); cout<<p->data<<" "<<p->bf<<endl; Q.pop(); if(p->left!=NULL){ Q.push(p->left); } if(p->right!=NULL){ Q.push(p->right); } } } int main(){ Node* root=NULL; int arr[]={16,3,7,11,9,26,18,14,15}; for(int i=0;i<sizeof(arr)/sizeof(int);i++){ Insert(root,arr[i]); } LevelTraversal(root);//結果應為:11 7 18 3 9 15 26 14 16 cout<<endl; Remove(root,16); LevelTraversal(root); cout<<endl; return 0; } //11 1 //7 0 //18 -1 //3 0 //9 0 //15 0 //26 0 //14 0 //16 0 // //11 1 //7 0 //18 -1 //3 0 //9 0 //15 -1 //26 0 //14 0