AVL樹(高度平衡的二叉搜尋樹)平衡因子的調節和旋轉
阿新 • • 發佈:2018-12-25
1.什麼叫AVL樹?
AVL樹又稱為高度平衡的二叉搜尋樹,它能保持二叉樹的高度平衡,儘量降低二叉樹的高度,減少樹的平均搜尋長度(儘量使這棵樹保持為完全二叉樹,這樣就能提高搜尋效率)。2.AVL樹的性質
(1)左子樹和右子樹的高度之差的絕對值不超過1(2) 樹中的每個左子樹和右子樹都是AVL樹
(3) 每個節點都有一個平衡因子(balance factor--bf),任一節點的平衡因子是-1,0,1。(每個節點的平衡因子等於右子樹的高度減去左子 樹的高度)
3.AVL樹節點的定義
template <typename K,typename V> struct AVLTreeNode { K _key; V _value; int _bf; //平衡因子,只能取值為-1,1,0 AVLTreeNode<K, V>* _left; AVLTreeNode<K, V>* _right; AVLTreeNode<K, V>* _parent; AVLTreeNode(const K& key, const V& value) :_key(key) , _value(value) , _bf(0) , _left(NULL) , _right(NULL) , _parent(NULL) {} };
4.AVL樹左單旋的情況
對應程式碼實現:
void _RotateL(Node* &parent) { //1.將要修改的結點標記起來 Node* SubR = parent->_right; Node* SubRL = SubR->_left; Node* pparent = parent->_parent; //2.重新鏈上SubR結點 SubR->_left = parent; SubR->_parent = pparent; SubR->_bf = 0; //4.重新鏈上parent結點 parent->_right = SubRL; parent->_parent = SubR; parent->_bf = 0; //5.改變pparent的指向結點 if (pparent == NULL) _root = SubR; else if (pparent->_left == parent) pparent->_left = SubR; else pparent->_right = SubR; //4.重新鏈上SubRL結點 if (SubRL != NULL) SubRL->_parent = parent; }
5.AVL樹右單旋的情況
對應的程式碼實現:
void _RotateR(Node* &parent) { //1.將要修改的結點標記起來 Node* SubL = parent->_left; Node* SubLR = SubL->_right; Node* pparent = parent->_parent; //2.重新鏈上SubL結點 SubL->_right = parent; SubL->_parent = parent->_parent; SubL->_bf = 0; //3.重新鏈上parent結點 parent->_left = SubLR; parent->_parent = SubL; parent->_bf = 0; //4.改變pparent的指向結點 if (pparent == NULL) _root = SubL; else if (pparent->_left == parent) pparent->_left = SubL; else pparent->_right = SubL; //5.重新鏈上SubRL結點 if (SubLR != NULL) SubLR->_parent = parent; }
6.AVL樹平衡因子的調節 (1)插入的資料只能影響祖先結點的平衡因子; (2)當某個平衡因子從0變成1或者-1,需要繼續調整祖先結點的平衡因子,直到根節點; (3)當某個平衡因子從-1或者1變成0,則不需要調整祖先的平衡因子了,因為平衡因子在插入資料之後變成0,證明整棵樹的高度沒有發生變化;
(4)當平衡因子在插入資料之後變成-2或者2,需要通過旋轉來降低它的高度,使它繼續保持AVL樹的性質 7.AVL樹進行左右雙旋的情況(注意平衡因子的調節)
程式碼實現:
void _RotateLR(Node* &parent)
{
//雙旋的時候在某些情況下會導致bf發生異常
Node* SubL = parent->_left;
Node* SubLR = SubL->_right;
int bf = SubLR->_bf;
_RotateL(parent->_left);
_RotateR(parent);
if (bf == -1)
{
parent->_bf = 1;
SubL->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
SubL->_bf = -1;
}
else
{
SubL->_bf = parent->_bf = 0;
}
SubLR->_bf = 0;
}
8.同樣的方法可以得到右左雙旋時平衡因子的變化
(1)SubRL->_bf==0 parent->_bf=SubR->_bf=0; (2)SubRL->_bf==-1 parent->_bf=0 SubR->_bf=1; (3)SubRL->_bf==1 parent->_bf=-1 SubR->_bf=0; 程式碼實現:
void _RotateRL(Node* &parent)
{
Node* SubR = parent->_right;
Node* SubRL = SubR->_left;
int bf = SubRL->_bf;
_RotateR(parent->_right);
_RotateL(parent);
if (bf == 1)
{
parent->_bf = -1;
SubR->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
SubR->_bf = 1;
}
else
{
SubR->_bf = parent->_bf = 0;
}
SubRL->_bf = 0;
}