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