Treap树的基本操作

来源:互联网 发布:大学生单片机自学视频 编辑:程序博客网 时间:2024/05/21 10:59

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;
 
voidTreap_Insert(Treap_Node *&P,intvalue) //节点指针一定要传递引用 p为要插入树的根节点
 
{
 
  if(!P) //1当P为空时
 
  {
 
    P=newTreap_Node;
 
    P->value=value;
 
    P->fix=rand();//生成随机的修正值 fix为节点的优先值
 
  }
 
  elseif (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         #endregion12 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                 else45                 {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                         else55                         {56                             //否则“右旋”57                             tree = RotateRR(tree);58                         }59 60                         //继续旋转61                         tree = Remove(key, value, tree);62                     }63                     else64                     {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 0
原创粉丝点击