Treap樹的基本操作

3. Treap的操作

同其他樹形結構一樣,treap的基本操作有:查找,插入,刪除等。

3.1    查找

同其他二叉樹一樣,treap的查找過程就是二分查找的過程,複雜度爲O(lg n)。

3.2    插入

在Treap 中插入元素,與在BST 中插入方法相似。首先找到合適的插入位置,然後建立新的節點,存儲元素。但是要注意新的節點會有一個優先級屬性,該值可能會破壞堆序,因此我們要根據需要進行恰當的旋轉。具體方法如下:

1. 從根節點開始插入;

2. 如果要插入的值小於等於當前節點的值,在當前節點的左子樹中插入,插入後如果左子節點的優先級小於當前節點的優先級,對當前節點進行右旋;

3. 如果要插入的值大於當前節點的值,在當前節點的右子樹中插入,插入後如果右子節點的優先級小於當前節點的優先級,對當前節點進行左旋;

4. 如果當前節點爲空節點,在此建立新的節點,該節點的值爲要插入的值,左右子樹爲空,插入成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Treap_Node *root;
 
void Treap_Insert(Treap_Node *&P,int value) //節點指針一定要傳遞引用 p爲要插入樹的根節點
 
{
 
  if (!P) //1 當P爲空時
 
  {
 
    P=new Treap_Node;
 
    P->value=value;
 
    P->fix=rand();//生成隨機的修正值 fix爲節點的優先值
 
  }
 
  else if (value <= P->value)
 
  {
 
    Treap_Insert(P->left,r);
 
    if (P->left->fix < P->fix)
 
      Treap_Right_Rotate(P);//左子節點優先級值小於當前節點優先級值,右旋當前節點
 
  }
 
  else
 
  {
 
    Treap_Insert(P->right,r);
 
    if (P->right->fix < P->fix)
 
      Treap_Left_Rotate(P);//右子節點修正值小於當前節點修正值,左旋當前節點
 
  }
 
}

3.3:刪除

  跟普通的二叉查找樹一樣,刪除結點存在三種情況。

①:葉子結點

      跟普通查找樹一樣,直接釋放本節點即可。

②:單孩子結點

     跟普通查找樹一樣操作。

③:滿孩子結點

    其實在treap中刪除滿孩子結點有兩種方式。

第一種:跟普通的二叉查找樹一樣,找到“右子樹”的最左結點(15),拷貝元素的值,但不拷貝元素的優先級,然後在右子樹中

           刪除“結點15”即可,最終效果如下圖。

第二種:將”結點下旋“,直到該節點不是”滿孩子的情況“,該賦null的賦null,該將孩子結點頂上的就頂上,如下圖:

當然從理論上來說,第二種刪除方法更合理,這裏我寫的就是第二種情況的代碼。

複製代碼
 1         #region 刪除當前樹中的節點
 2         /// <summary>
 3         /// 刪除當前樹中的節點
 4         /// </summary>
 5         /// <param name="key"></param>
 6         /// <returns></returns>
 7         public void Remove(K key, V value)
 8         {
 9             node = Remove(key, value, node);
10         }
11         #endregion
12 
13         #region 刪除當前樹中的節點
14         /// <summary>
15         /// 刪除當前樹中的節點
16         /// </summary>
17         /// <param name="key"></param>
18         /// <param name="tree"></param>
19         /// <returns></returns>
20         public TreapNode<K, V> Remove(K key, V value, TreapNode<K, V> tree)
21         {
22             if (tree == null)
23                 return null;
24 
25             //左子樹
26             if (key.CompareTo(tree.key) < 0)
27             {
28                 tree.left = Remove(key, value, tree.left);
29             }
30             //右子樹
31             if (key.CompareTo(tree.key) > 0)
32             {
33                 tree.right = Remove(key, value, tree.right);
34             }
35             /*相等的情況*/
36             if (key.CompareTo(tree.key) == 0)
37             {
38                 //判斷裏面的HashSet是否有多值
39                 if (tree.attach.Count > 1)
40                 {
41                     //實現惰性刪除
42                     tree.attach.Remove(value);
43                 }
44                 else
45                 {
46                     //有兩個孩子的情況
47                     if (tree.left != null && tree.right != null)
48                     {
49                         //如果左孩子的優先級低就需要“左旋”
50                         if (tree.left.priority < tree.right.priority)
51                         {
52                             tree = RotateLL(tree);
53                         }
54                         else
55                         {
56                             //否則“右旋”
57                             tree = RotateRR(tree);
58                         }
59 
60                         //繼續旋轉
61                         tree = Remove(key, value, tree);
62                     }
63                     else
64                     {
65                         //如果旋轉後已經變成了葉子節點則直接刪除
66                         if (tree == null)
67                             return null;
68 
69                         //最後就是單支樹
70                         tree = tree.left == null ? tree.right : tree.left;
71                     }
72                 }
73             }
74 
75             return tree;
76         }
77         #endregion
複製代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章