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
复制代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值