zoukankan      html  css  js  c++  java
  • 树堆(Treap)

    平衡树

    简介:

    平衡二叉树(Balanced Binary Tree)具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。

    Treap:

    简介:

    Treap代码实现相对简单的一个算法,Treap是 heap+Tree,既满足堆的性质也满足平衡树的性质,一棵树的节点上有一个data用于存数据,fix是一个堆的优先级(假设我们是小顶堆),key是平衡树的比较值;key一般是给出的,然而fix我们随机生成,这样的随机会使得平衡树比较平衡。假设一棵排序二叉树插入一组有序的数,就会使得树退化为一条链。我们在插入的时候为每个节点随机生成一个fix(优先级)。插入时满足排序二叉树的性质。插入完成时检查是否满足堆的性质,并进行旋转操作使他满足堆的性质。

    旋转操作:

    为了满足堆的性质,我们需要对这棵树进行旋转以达到堆的性质。旋转操作看图

    如图是旋转操作,我用的是指针链式的写法:所以,每次旋转需要调整两个节点的父子关系。以及指向P或者Q的那个指针。
    下面给出指针的写法
    void rotate(Node* &o,int d)
    {
        Node *k=o->ch[d^1];
        o->ch[d^1]=k->ch[d];
        k->ch[d]=o;
        o=k;
    }
    上面是旋转操作,d传0代表左旋,d为1代表右旋;

    当我们了解旋转操作后,接下来;


    插入元素操作:

    首先根据排序二叉树的性质找到叶子节点,将新的元素插入到叶子节点。当插入之后会破坏堆的性质,然后进行旋转操作让他满足堆的性质,因为那样旋转不会破坏排序二叉树的性质的。所以旋转只需要考虑堆的性质。


    删除操作:

    用排序二叉树的性质去找要删除的元素位置,找到之后判断是否左右都是有儿子,如果不是直接删除,把指向他的指针,直接指向他的儿子节点。如果是就需要通过旋转操作。把需要删除的元素往下旋转。旋转时为了满足堆的性质(如果是小顶堆)需要比较左右儿子的大小,将该元素与小值的儿子进行旋转。


     
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 using namespace std;
      5 int sz;
      6 const int maxn=1e6+10;
      7 struct Node
      8 {
      9     Node *ch[2];
     10     int r,v,info;//v是顾客优先级,info是顾客的编号,r由rand()生成
     11     int cmp(int x)
     12     {
     13         if(x==v) return -1;
     14         return x<v? 0:1;
     15     }
     16 }T[maxn];
     17 Node * newnode(int _v,int _info)
     18 {
     19     Node *res=&T[sz];
     20     T[sz].v=_v,T[sz].info=_info;
     21     T[sz].r=rand();
     22     T[sz].ch[0]=T[sz].ch[1]=NULL;
     23     sz++;
     24     return res;
     25 }
     26 void rotate(Node* &o,int d)
     27 {
     28     Node *k=o->ch[d^1];
     29     o->ch[d^1]=k->ch[d];
     30     k->ch[d]=o;
     31     o=k;
     32 }
     33 void insert(Node* &o,int v,int info)
     34 {
     35     if(o==NULL) o=newnode(v,info);
     36     else
     37     {
     38         int d= v < o->v?0:1;
     39         insert(o->ch[d],v,info);
     40         if(o->ch[d]->r > o->r)
     41             rotate(o,d^1);
     42     }
     43 }
     44 void remove(Node *&o,int v)
     45 {
     46     int d=o->cmp(v);
     47     if(d==-1)
     48     {
     49         if(o->ch[0] && o->ch[1])
     50         {
     51             int d2 = o->ch[0]->r < o->ch[1]->r ?0:1;
     52             rotate(o,d2);
     53             remove(o->ch[d2],v);
     54         }
     55         else
     56         {
     57             if(o->ch[0]==NULL)o=o->ch[1];
     58             else o=o->ch[0];
     59         }
     60     }
     61     else remove(o->ch[d],v);
     62 }
     63 int find_max(Node *o)//找到最大v值
     64 {
     65     if(o->ch[1]==NULL)
     66     {
     67         printf("%d
    ",o->info);
     68         return o->v;
     69     }
     70     return find_max(o->ch[1]);
     71 }
     72 int find_min(Node *o)//找到最小v值
     73 {
     74     if(o->ch[0]==NULL)
     75     {
     76         printf("%d
    ",o->info);
     77         return o->v;
     78     }
     79     return find_min(o->ch[0]);
     80 }
     81 int main()
     82 {
     83     int op;
     84     Node *root=NULL;
     85     sz=0;
     86     while(scanf("%d",&op)==1&&op)
     87     {
     88         if(op==1)
     89         {
     90             int info,v;
     91             scanf("%d%d",&info,&v);
     92             insert(root,v,info);
     93         }
     94         else if(op==2)
     95         {
     96             if(root==NULL)
     97             {
     98                 printf("0
    ");
     99                 continue;
    100             }
    101             int v=find_max(root);
    102             remove(root,v);
    103         }
    104         else if(op==3)
    105         {
    106             if(root==NULL)
    107             {
    108                 printf("0
    ");
    109                 continue;
    110             }
    111             int v=find_min(root);
    112             remove(root,v);
    113         }
    114     }
    115     return 0;
    116 }
     
    优先队列的实现。
  • 相关阅读:
    luogu P1641 [SCOI2010]生成字符串
    luogu P2662 牛场围栏
    luogu P3193 [HNOI2008]GT考试
    luogu P3293 [SCOI2016]美味
    luogu P2048 [NOI2010]超级钢琴
    Wannafly挑战赛21 E 未来城市规划
    luogu P2770 航空路线问题
    luogu P4082 [USACO17DEC]Push a Box
    运维交流平台
    elk之[logstash-input-file]插件使用详解
  • 原文地址:https://www.cnblogs.com/coded-ream/p/7207913.html
Copyright © 2011-2022 走看看