AVL樹C++實現

1. AVL 樹本質上仍是一棵二叉搜索樹,它的特色是:node

  • 自己首先是一棵二叉搜索樹。
  • 帶有平衡條件: 每一個結點的左右子樹的高度之差的絕對值(平衡因子) 最多爲 1。

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

  • 在左兒子的左子樹((data < p->data) AND (data < p->left->data)), 「外邊」,要作單旋轉。
  • 在左兒子的右子樹((data < p->data) AND (data > p->left->data0)),「內部」,要作雙旋轉。

2) 在結點的右兒子(data > p->data)htm

  • 在右兒子的左子樹((data > p->data) AND (data < p->right->data)),「內部」,要作雙旋轉。
  • 在右兒子的右子樹((data > p->data) AND (data > p->right->data)),「外邊」,要作單旋轉。
 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

相關文章
相關標籤/搜索