Treap 学习总结

Treap是一种BST,可以山寨set,另外还可以实现set实现不了的“名次树”。它可以说是一个满足堆性质的BST。“堆性质”是为了维护它的平衡,对于每个节点,都给它随机一个值,作为堆性质的关键字。所以,Treap的使用要看一点点人品,随机出的优先值在大多数情况下还是可以使BST趋于平衡的,各个操作的期望复杂度是O(logn)。

写一个能实现名次树的Treap需要多开一个size数组,支持以下操作:
1.插入新节点
2.删除某节点
3.查询键值为x的节点
4.查询名次为x的节点
5.查询键值为x的节点的名次

对于插入,先随机一个用于比较优先级的键值,然后按照普通BST的方式插入,插入完成后根据键值进行旋转,直至优先级满足堆性质。
对于删除,如果待删除节点只有一棵子树,直接把它的子节点连接到它的父节点即可,否则就在满足堆性质的前提下旋转(左子树优先级大于右子树,那么把左子树旋转到根),待删除节点深度变大,总会在某次旋转后变成叶子节点,这时也可以直接删除。
对于查询,查询键值就如同普通的BST。查询第k小的从根节点开始递归,如果左子树大小大于k+1,进入左子树,否则进入右子树,并且k -= 左子树大小+1,直到k等于当前结点左子树大小+1为止。查询键值为x的节点名次就是它的左子树大小+1。

Treap理解起来很容易,代码相比其他BST也算好写,就作为自己第一个学习的BST了。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

struct Node
{
    int lc, rc, fa, size, d, k;
    Node() {lc = rc = size = 0;}
    void init(int _fa, int _k)
    {
        fa = _fa, k = _k, d = rand(), size = 1;
    }   
};

struct Treap
{   
    #define M 1111
    Node T[M]; int num, root;
    Treap () {memset(T, 0, sizeof T); num = root = 0;}

    void Rota_L(int rt) // lc be the root
    {
        T[0].size = 0;
        int Fa = T[rt].fa, Lc = T[rt].lc, Rc = T[Lc].rc;
        if(rt == root) root = Lc, T[Lc].fa = 0;
        else
        {
            T[Lc].fa = Fa;
            if(T[Fa].lc == rt) T[Fa].lc = Lc;
            if(T[Fa].rc == rt) T[Fa].rc = Lc;
        }
        T[Rc].fa = rt, T[rt].fa = Lc;
        T[rt].lc = Rc, T[Lc].rc = rt;
        int t = T[rt].size;
        T[rt].size -= (T[Lc].size - T[Rc].size);
        T[Lc].size = t; 

    }
    void Rota_R(int rt) // rc be the root
    {
        T[0].size = 0;
        int Fa = T[rt].fa, Rc = T[rt].rc, Lc = T[Rc].lc;
        if(rt == root) root = Rc, T[Rc].fa = 0;
        else
        {
            T[Rc].fa = Fa;
            if(T[Fa].lc == rt) T[Fa].lc = Rc;
            if(T[Fa].rc == rt) T[Fa].rc = Rc;
        }
        T[Lc].fa = rt, T[rt].fa = Rc;
        T[rt].rc = Lc, T[Rc].lc = rt;
        int t = T[rt].size;
        T[rt].size -= (T[Rc].size - T[Lc].size);
        T[Rc].size = t; 
    }

    void change(int rt, int k)
    {
        if(!rt) return ;
        T[rt].size+=k; change(T[rt].fa, k);
    }

    void Maintain(int rt)
    {
        Node Rt = T[rt], Fa = T[T[rt].fa];
        if(Rt.d < Fa.d || !Rt.fa)  return ;
        if(Fa.lc == rt) Rota_L(Rt.fa);
        if(Fa.rc == rt) Rota_R(Rt.fa);
        Maintain(rt);
    }

    bool insert(int rt, int k)
    {
        if(!rt) {root = ++num; T[num].init(0, k); return 1;}
        if(T[rt].k == k) return 0;
        if(T[rt].k < k)
        {
            if(T[rt].rc) return insert(T[rt].rc, k);
            T[rt].rc = ++num; change(rt, 1);
            T[num].init(rt, k);
            Maintain(num);
            return 1;
        }
        if(T[rt].k > k)
        {
            if(T[rt].lc) return insert(T[rt].lc, k);
            T[rt].lc = ++num; change(rt, 1);
            T[num].init(rt, k);
            Maintain(num);
            return 1;
        }
    }
    bool insert(int k) {return insert(root, k); }

    int rank(int rt, int k)
    {
        if(!rt) return 0;
        T[0].size = 0;
        int Lc = T[rt].lc, Rc = T[rt].rc;
        if(k == T[rt].k) return T[Lc].size+1;
        if(k <  T[rt].k) return rank(Lc, k);
        if(k >  T[rt].k) return rank(Rc, k) + T[Lc].size + 1;
    }
    int rank(int k) {return rank(root, k);}

    int find(int rt, int k)
    {
        if(!rt) return 0; T[0].size = 0;
        int Lc = T[rt].lc, Rc = T[rt].rc;
        if(k == T[Lc].size+1) return rt;
        if(k <  T[Lc].size+1) return find(Lc, k);
        if(k >  T[Lc].size+1) return find(Rc, k-T[Lc].size-1);
    }
    int find(int k) {return find(root, k);}

    void dele(int rt)
    {
        int Fa = T[rt].fa, Lc = T[rt].lc, Rc = T[rt].rc;
        if(!Lc || !Rc)
        {
            int nxt = Lc ? Lc: Rc;
            if(root == rt) { root = nxt; return ;}
            if(T[Fa].lc == rt) T[Fa].lc = nxt; 
            if(T[Fa].rc == rt) T[Fa].rc = nxt; 
            change(Fa, -1); T[nxt].fa = Fa; 
            return ;
        }
        if(T[Lc].d > T[Rc].d) Rota_L(rt); else Rota_R(rt);
        dele(rt);
    }
    bool del(int rt, int k)
    {
        if(!rt) return 0;
        if(T[rt].k == k) {dele(rt); return 1;}
        if(T[rt].k < k) return del(T[rt].rc, k);
        if(T[rt].k > k) return del(T[rt].lc, k);
    }
    bool del(int k) {return del(root, k);}

    void print(int rt)
    {
        if(!rt) return ;
        print(T[rt].lc);
        printf("%d ", T[rt].k);
        print(T[rt].rc);
    }
    void print() {print(root); putchar('\n');}
};

int main()
{
    srand(time(NULL));
    Treap test;
    int n, q; scanf("%d", &q);
    while(q--)
    {
        int x, c; scanf("%d %d", &x, &c);
        if(x == 1) test.insert(c);
        if(x == 2) test.del(c);
        if(x == 3) printf("%d\n", test.rank(c));
        if(x == 4) printf("%d\n", test.T[test.find(c)].k);
        test.print(); 
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值