二叉樹中全部結點的平衡因子BF
的絕對值均小於等於1
,即:\(|BF|\leq1\)。平衡因子是,結點的左子樹高度減去右子樹的高度。平衡因子BF
絕對值大於1
表示二叉樹失衡。ios
兩種狀況:c++
1
,向該結點的左子樹插入結點,該結點的平衡因子變爲2
,致使失衡;-1
,向該結點的右子樹插入結點,該結點的平衡因子變爲-2
,致使失衡。如何解決失衡?函數
關鍵問題是要找到失衡結點,離插入結點最近的失衡結點。this
失衡結點的特色:spa
解決辦法:指針
採用遞歸的方法進行插入,插入成功後會進行回代,所以在回代的過程當中能夠判斷結點是否失衡,從而可以找到離插入結點最近的失衡結點。code
/* 一、判斷二叉樹是否失衡,若失衡返回true,不然返回false 二、若二叉樹失衡,則返回離插入結點最近的結點 */ bool IsBalanced(BTNode<T> *&T,T key) { if(!T) { //未找到值爲key的結點,進行插入 Insert(key); return true; } else if(T->data==key) { return false;//找到結點key,不可插入 } else if(T->data>key) { bool temp=IsBalanced(T->lchild,key);//若是temp爲真,則表示結點插入到T的左子樹 if(temp) { //判斷T的平衡因子,若等於1,則須要調整 } } else { //同上 } }
附上完整代碼:排序
#include <iostream> using namespace std; //結點結構 template <class T> class BTNode { public: //結點數據 T data; //左右孩子指針 BTNode<T> *lchild, *rchild; //添加平衡因子 int BF; public: //構造函數 BTNode(T D, int bf = 0, BTNode<T> *l = NULL, BTNode<T> *r = NULL) : data(D), BF(bf), lchild(l), rchild(r) {} }; //AVL平衡二叉樹 template <class T> class AVLTree { //私有屬性 private: //二叉樹根節點 BTNode<T> *root; private: //銷燬二叉樹 void Destory(BTNode<T> *&rt) { if(rt) { this->Destory(rt->lchild); this->Destory(rt->rchild); delete rt; } } //二叉樹查找 //和二叉排序樹的查找方法同樣 bool SearchAVL(BTNode<T> *rt, T key, BTNode<T> *&p, BTNode<T> *f = NULL) { if (!rt) //查找失敗,返回false { p = f; //p指向查找路徑上最後訪問的元素 return false; } else if (rt->data == key) //查找成功,返回true { p = rt; //p指向查找到的元素 return true; } else if (rt->data > key) { return this->SearchAVL(rt->lchild, key, p, rt); } else { return this->SearchAVL(rt->rchild, key, p, rt); } } //左旋處理 void L_Rotate(BTNode<T> *&p) { BTNode<T> *R = p->rchild; //R指向p的左孩子 p->rchild = R->lchild; //p的右孩子指向R的左孩子 R->lchild = p; //R的左孩子指向p p = R; //該二叉樹的根節點變爲R } //右旋處理 void R_Rotate(BTNode<T> *&p) { BTNode<T> *L = p->lchild; p->lchild = L->rchild; L->rchild = p; p = L; } //左平衡處理,已知結點的平衡因子是+2,所以一定是在該結點的左子樹插入的結點 //二叉排序樹的根節點平衡因子的絕對值大於1,需進行平衡處理 void LeftBalance(BTNode<T> *&p) { BTNode<T> *L = p->lchild; //L指向p的左孩子 /* 判斷L的平衡因子 若平衡因子爲1,表示新節點插入在L的左子樹 若平衡因子爲-1,表示新節點插入在L的右子樹 */ switch (L->BF) { case 1: //結點插入在L的左子樹,需進行右旋處理 this->R_Rotate(p); p->BF = 0; p->rchild->BF = 0; //右旋處理後,需改變旋轉結點的平衡因子 break; case -1: { //結點插入在L的右子樹,需進行雙旋處理 BTNode<T> *L_R = L->rchild; switch (L_R->BF) { case 1: //結點插入在L_R的左子樹 p->BF = -1; L->BF = 0; break; case 0: //結點L_R就是新插入的結點 p->BF = 0; L->BF = 0; break; case -1: //結點插入在L_R的右子樹 p->BF = 0; L->BF = 1; break; } L_R->BF = 0; this->L_Rotate(L); //先左旋處理 this->R_Rotate(p); //後右旋處理 break; } } } //右平衡處理,已知結點的平衡因子是-2,所以一定是在該結點的右子樹插入的結點 void RightBalance(BTNode<T> *&p) { BTNode<T> *R = p->rchild; switch (R->BF) { case 1: { //新節點插入在R的左子樹上,需進行雙旋處理 BTNode<T> *R_L = R->lchild; switch (R_L->BF) { case 1: //結點插入在R_L的左子樹上 p->BF = 0; R->BF = -1; break; case 0: //R_L就是新插入的結點 p->BF = 0; R->BF = 0; break; case -1: //結點插入在R_L的右子樹上 p->BF = 1; R->BF = 0; break; } R_L->BF = 0; this->R_Rotate(R); //先右旋處理 this->L_Rotate(p); //後左旋處理 break; } case -1: //新節點插入在R的右子樹上,需進行左旋處理 p->BF = 0; R->BF = 0; this->L_Rotate(p); break; } } //向二叉樹中插入結點,並保持平衡 bool InsertAVL(BTNode<T> *&rt, T key, bool &taller) //taller用來記錄二叉樹是否長高 { if (!rt) //表示未在二叉樹中找到結點值爲key的結點,需插入結點 { rt = new BTNode<T>(key, 0, NULL, NULL); //將新節點賦值給rt指針 taller = true; return true; } else if (rt->data == key) //存在key,返回false { taller = false; return false; } else if (rt->data > key) { if (!this->InsertAVL(rt->lchild, key, taller)) //未插入結點 { return false; } if (taller) //二叉樹長高,表示遞歸回到rt結點 { switch (rt->BF) { case 1: //結點rt的平衡因子爲1,而又在左子樹新插入結點,故結點rt失衡,需調整 this->LeftBalance(rt); taller = false; //維護狀態,在失衡結點調整後,其祖父結點的平衡因子不會變,故不用更改,結束此模塊遞歸 break; case 0: //結點rt的平衡因子爲0,在左子樹插入結點,結點rt不會失衡,不用調整 rt->BF = 1; taller = true; //插入新節點,二叉樹高度增長,繼續此模塊遞歸,找到失衡結點 break; case -1: //結點rt的平衡因子爲-1,在左子樹插入結點,結點rt不會失衡,不用調整 rt->BF = 0; taller = false; //插入新節點,二叉樹高度未增,結束此模塊遞歸 break; } } return true; } else { if (!this->InsertAVL(rt->rchild, key, taller)) //未插入結點 { return false; } if (taller) //二叉樹長高,表示遞歸回到rt結點 { switch (rt->BF) { case 1: //結點rt的平衡因子爲1,而又在右子樹新插入結點,故結點rt不會失衡 rt->BF = 0; taller = false; //插入新節點,二叉樹高度未增,結束此模塊遞歸 break; case 0: //結點rt的平衡因子爲0,在右子樹插入結點,結點rt不會失衡,不用調整 rt->BF = -1; taller = true; //插入新節點,二叉樹高度增長,繼續此模塊遞歸,找到失衡結點 break; case -1: //結點rt的平衡因子爲-1,在右子樹插入結點,結點rt會失衡,用調整 this->RightBalance(rt); taller = false; //維護狀態,在失衡結點調整後,其祖父結點的平衡因子不會變,故不用更改,結束此模塊遞歸 break; } } return true; } } //前序遍歷 void PreOrder(BTNode<T> *rt) { if (rt) { cout << rt->data << " "; this->PreOrder(rt->lchild); this->PreOrder(rt->rchild); } } //中序遍歷 void InOrder(BTNode<T> *rt) { if(rt) { this->InOrder(rt->lchild); cout<<rt->data<<" "; this->InOrder(rt->rchild); } } public: //構造函數 AVLTree() : root(NULL) {} //拷貝構造函數 AVLTree(const AVLTree<T> &t) {} //銷燬二叉樹 void Destory() { this->Destory(this->root); this->root=NULL; } //析構函數 ~AVLTree() { this->Destory(this->root); } //前序遍歷 void PreOrder() { this->PreOrder(this->root); } //中序遍歷 void InOrder() { this->InOrder(this->root); } //二叉樹查找 bool Search(T key, BTNode<T> *&p = NULL) { return this->SearchAVL(this->root, key, p, NULL); } //插入操做 bool Insert(T key) { bool p; return this->InsertAVL(this->root, key, p); } }; int main() { AVLTree<int> temp; for (int i = 0; i < 10; i++) { temp.Insert(i); } temp.PreOrder(); cout<<endl; temp.InOrder(); cout<<endl; system("pause"); return 0; }