1. AVL 樹本質上仍是一棵二叉搜索樹,它的特色是:node
2. 數據結構定義git
AVL樹節點類:github
1 template <typename T> 2 class AVLTreeNode { 3 public: 4 T key; 5 AVLTreeNode<T>* parent; 6 AVLTreeNode<T>* left; 7 AVLTreeNode<T>* right; 8 AVLTreeNode():key(T()), parent(NULL), left(NULL), right(NULL) {} 9 };
AVL樹類:編程
1 template <typename T> 2 class AVLTree { 3 public: 4 AVLTree():root(NIL) {}; 5 void inorder_tree_walk(AVLTreeNode<T>* proot); //中序遍歷整棵樹, 參數爲AVL樹的根節點 6 int insert_key(const T& k); 7 int delete_key(const T& k); 8 AVLTreeNode<T>* tree_search(const T& k) const; //根據關鍵字k搜索AVL樹,返回對應的節點指針 9 AVLTreeNode<T>* get_root() const; 10 ~AVLTree(); 11 12 private: 13 AVLTreeNode<T>* root; 14 static AVLTreeNode<T>* NIL; 15 int getDepth(const AVLTreeNode<T>* pnode) const; //獲取以pnode爲根節點的樹的深度 16 int insert_Key(const T& k, AVLTreeNode<T>* pnode); 17 int delete_key(const T& k, AVLTreeNode<T>* pnode); 18 AVLTreeNode<T>* tree_minimum(AVLTreeNode<T>* pnode); //獲取最小值節點(最左邊節點) 19 void make_empty(AVLTreeNode<T>* proot); 20 void avl_translate(AVLTreeNode<T>* node_u, AVLTreeNode<T>* node_v); 21 void singleRotateWithL(AVLTreeNode<T>* pnode); //左單旋 22 void singleRotateWithR(AVLTreeNode<T>* pnode); //右單旋 23 void avl_delete_fixup(AVLTreeNode<T>* pnode, int flag); //節點刪除後調整AVL樹, 使其知足AVL樹的性質 24 inline void rotateWithLR(AVLTreeNode<T>* pnode); //先左後右雙旋 25 inline void rotateWithRL(AVLTreeNode<T>* pnode); //先右後左雙旋 26 };
3. 假設有一個結點的平衡因子爲 2(在 AVL 樹中, 最大就是 2, 由於結點是一個一個地插入到樹中的, 一旦出現不平衡的狀態就會當即進行調整, 所以平衡因子最大不可能超過 2),那麼就須要進行調整。因爲任意一個結點最多隻有兩個兒子,因此當高度不平衡時,只多是如下四種狀況形成的:數據結構
狀況 1 和 4 是關於該點的鏡像對稱,一樣,狀況 2 和 3 也是一對鏡像對稱。所以,理論上只有兩種狀況,固然了,從編程的角度來看仍是四種狀況。第一種狀況是插入發生在「外邊」 的狀況(即左-左的狀況或右-右的狀況),該狀況能夠經過對樹的一次單旋轉來完成調整。 第二種狀況是插入發生在「內部」的狀況(即左-右的狀況或右-左的狀況),該狀況要經過稍微複雜些的雙旋轉來處理。
左單旋:測試
1 template <typename T> 2 void AVLTree<T>::singleRotateWithL(AVLTreeNode<T>* pnode) { 3 AVLTreeNode<T> *tmpnode_x = pnode->right; 4 pnode->right = tmpnode_x->left; 5 if(tmpnode_x->left != NIL) 6 tmpnode_x->left->parent = pnode; 7 tmpnode_x->parent = pnode->parent; 8 if(pnode->parent == NIL) 9 root = tmpnode_x; 10 else if(pnode == pnode->parent->left) 11 pnode->parent->left = tmpnode_x; 12 else 13 pnode->parent->right = tmpnode_x; 14 tmpnode_x->left = pnode; 15 pnode->parent = tmpnode_x; 16 }
右單旋:spa
1 template <typename T> 2 void AVLTree<T>::singleRotateWithR(AVLTreeNode<T>* pnode) { 3 AVLTreeNode<T> *tmpnode_x = pnode->left; 4 pnode->left = tmpnode_x->right; 5 if(tmpnode_x->right != NIL) 6 tmpnode_x->right->parent = pnode; 7 tmpnode_x->parent = pnode->parent; 8 if(pnode->parent == NIL) 9 root = tmpnode_x; 10 else if(pnode == pnode->parent->left) 11 pnode->parent->left = tmpnode_x; 12 else 13 pnode->parent->right = tmpnode_x; 14 tmpnode_x->right = pnode; 15 pnode->parent = tmpnode_x; 16 }
雙旋能夠直接複用單旋的代碼:指針
1 template <typename T> 2 void AVLTree<T>::rotateWithLR(AVLTreeNode<T>* pnode) { 3 singleRotateWithL(pnode->left); 4 return singleRotateWithR(pnode); 5 } 6 7 template <typename T> 8 void AVLTree<T>::rotateWithRL(AVLTreeNode<T>* pnode) { 9 singleRotateWithR(pnode->right); 10 return singleRotateWithL(pnode); 11 }
4. 插入的核心思路是經過遞歸, 找到合適的位置, 插入新結點, 而後看新結點是否平衡(平衡因子是否爲 2),若是不平衡的話,就分紅兩種大狀況以及兩種小狀況:
1) 在結點的左兒子(data < p->data)code
2) 在結點的右兒子(data > p->data)htm
1 template <typename T> 2 int AVLTree<T>::insert_Key(const T& k, AVLTreeNode<T>* pnode) { 3 if(root == NIL) { 4 AVLTreeNode<T>* newnode = new AVLTreeNode<T>; 5 newnode->key = k; 6 newnode->left = NIL; 7 newnode->right = NIL; 8 newnode->parent = NIL; 9 root = newnode; 10 } 11 else { 12 if(k < pnode->key) { 13 if(pnode->left == NIL) { 14 AVLTreeNode<T>* newnode = new AVLTreeNode<T>; 15 newnode->key = k; 16 newnode->left = NIL; 17 newnode->right = NIL; 18 newnode->parent = pnode; 19 pnode->left = newnode; 20 } 21 else 22 insert_Key(k, pnode->left); 23 if(2 == (getDepth(pnode->left) - getDepth(pnode->right))) { 24 if(k < pnode->left->key) 25 singleRotateWithR(pnode); 26 else 27 rotateWithLR(pnode); 28 } 29 } 30 else { 31 if(pnode->right == NIL) { 32 AVLTreeNode<T>* newnode = new AVLTreeNode<T>; 33 newnode->key = k; 34 newnode->left = NIL; 35 newnode->right = NIL; 36 newnode->parent = pnode; 37 pnode->right = newnode; 38 } 39 else 40 insert_Key(k, pnode->right); 41 if(2 == (getDepth(pnode->right) - getDepth(pnode->left))) { 42 if(k > pnode->right->key) 43 singleRotateWithL(pnode); 44 else 45 rotateWithRL(pnode); 46 } 47 } 48 } 49 return 0; 50 }
5. AVL刪除
1 template <typename T> 2 int AVLTree<T>::delete_key(const T& k) { 3 int flag; 4 AVLTreeNode<T>* delnode = tree_search(k); 5 AVLTreeNode<T>* tmpnode_x = delnode->parent; 6 if(delnode == tmpnode_x->left) 7 flag = LC; 8 else 9 flag = RC; 10 if(delnode->left == NIL) 11 avl_translate(delnode, delnode->right); 12 else if(delnode->right == NIL) 13 avl_translate(delnode, delnode->left); 14 else { 15 AVLTreeNode<T>* tmpnode_y = tree_minimum(delnode->right); 16 tmpnode_x = tmpnode_y->parent; 17 if(tmpnode_y == tmpnode_x->left) 18 flag = LC; 19 else 20 flag = RC; 21 if(tmpnode_y->parent != delnode) { 22 avl_translate(tmpnode_y, tmpnode_y->right); 23 tmpnode_y->right = delnode->right; 24 tmpnode_y->right->parent = tmpnode_y; 25 } 26 avl_translate(delnode, tmpnode_y); 27 tmpnode_y->left = delnode->left; 28 tmpnode_y->left->parent = tmpnode_y; 29 } 30 avl_delete_fixup(tmpnode_x, flag); 31 return 0; 32 }
1 template <typename T> 2 void AVLTree<T>::avl_delete_fixup(AVLTreeNode<T>* pnode, int flag) { 3 int tmpflag = flag; 4 AVLTreeNode<T>* tmpnode_x = pnode; 5 while(tmpnode_x != NIL) { 6 if(tmpflag == LC) { 7 if(2 == (getDepth(tmpnode_x->right) - getDepth(tmpnode_x->left))) { 8 if(LH == (getDepth(tmpnode_x->right->left) - getDepth(tmpnode_x->right->right))) 9 rotateWithRL(tmpnode_x); 10 else 11 singleRotateWithL(tmpnode_x); 12 break; 13 } 14 } 15 else if(tmpflag == RC) { 16 if(2 == (getDepth(tmpnode_x->left) - getDepth(tmpnode_x->right))) { 17 if(RH == (getDepth(tmpnode_x->left->left) - getDepth(tmpnode_x->left->right))) 18 rotateWithLR(tmpnode_x); 19 else 20 singleRotateWithR(tmpnode_x); 21 break; 22 } 23 } 24 if(tmpnode_x == tmpnode_x->parent->left) 25 tmpflag = LC; 26 else if(tmpnode_x == tmpnode_x->parent->right) 27 tmpflag = RC; 28 tmpnode_x = tmpnode_x->parent; 29 } 30 }
簡單測試:
==========================我是華麗的分割線=================================
源碼猛戳{這裏}!
=====================================================================
參考資料:
http://www.luocong.com/dsaanotes/index-Z-H-11.htm#node_sec_10.1