平衡树

Posted ydddd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了平衡树相关的知识,希望对你有一定的参考价值。

平衡树

Treap实现

思路:

利用堆的性质, 让二叉搜索数满足堆的性质,从而达到logn的高度.
模板
具体解释看注释,注释也不多(逃)

代码:

/*
 * 平衡数Treap模板
 * Treap 可以理解为一棵树加上一个堆, 通过对每个节点赋予一个随机值
 * 在满足堆的性质的同时满足二叉搜索树的性质, 保证树的高度尽量为logn,
 * 这样就不会出现较坏的情况
 */
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6+10;
const int INF = 1e9;

struct Treap

    int l, r;//左儿子和右儿子的标号
    int data;//节点的随机值
    int val;//节点维护的值
    int cnt;//节点当前值的数量
    int size;//当前子树的值
treap[MAXN];
int cnt, root, n;//节点总数

void PushUp(int p)

    //向上更新
    treap[p].size = treap[treap[p].l].size+treap[treap[p].r].size+treap[p].cnt;


void RotateRight(int &p)

    //右旋操作
    int q = treap[p].l;
    treap[p].l = treap[q].r;
    treap[q].r = p;
    p = q;
    PushUp(treap[p].r);
    PushUp(p);


void RotateLeft(int &p)

    //左旋操作
    int q = treap[p].r;
    treap[p].r = treap[q].l;
    treap[q].l = p;
    p = q;
    PushUp(treap[p].l);
    PushUp(p);


int NewNode(int val)

    ++cnt;
    treap[cnt].val = val;
    treap[cnt].cnt = treap[cnt].size = 1;
    treap[cnt].data = rand();
    treap[cnt].l = treap[cnt].r = -1;//表示没有子节点
    return cnt;


void Build()

    //初始化建个树用来判断边界条件
    NewNode(-INF), NewNode(INF);
    root = 1;//根节点初始化
    treap[root].r = 2;
    PushUp(root);


void Insert(int &p, int val)

    //插入节点
    if (p == -1)
    
        //说明这个节点没有使用
        p = NewNode(val);
        return;
    
    if (val == treap[p].val)
    
        //查询到相同值
        treap[p].cnt++;
        PushUp(p);
        return;
    
    if (val < treap[p].val)
    
        //往左节点移动
        Insert(treap[p].l, val);
        //根据data值来调整树的高度
        if (treap[p].data < treap[treap[p].l].data)
            RotateRight(p);
    
    else
    
        //往右节点移动
        Insert(treap[p].r, val);
        if (treap[p].data < treap[treap[p].r].data)
            RotateLeft(p);
    
    PushUp(p);//更新


void Remove(int &p, int val)

    //删除节点即将要删除的点给移动到叶子节点再进行删除即可.
    if (p == -1)
        return;
    //不存在这个值
    if (val == treap[p].val)
    
        if (treap[p].cnt > 1)
        
            treap[p].cnt--;
            PushUp(p);
            return;
        
        if (treap[p].l != -1 || treap[p].r != -1)
        
            if (treap[p].r == -1 || treap[treap[p].l].data > treap[treap[p].r].data)
            
                RotateRight(p);
                Remove(treap[p].r, val);
            
            else
            
                RotateLeft(p);
                Remove(treap[p].l, val);
            
            PushUp(p);
        
        else
        
            p = -1;
            return;
        
    
    if (val < treap[p].val)
        Remove(treap[p].l, val);
    else
        Remove(treap[p].r, val);
    PushUp(p);


int GetRankByVal(int p, int val)

    //得到某个值的排名
    if (p == -1)
        return 0;
    if (val == treap[p].val)
        return treap[treap[p].l].size + 1;
    if (val < treap[p].val)
        return GetRankByVal(treap[p].l, val);
    return GetRankByVal(treap[p].r, val)+treap[treap[p].l].size+treap[p].cnt;


int GetValByRank(int p, int rank)

    //找到排名对应的值
    if (p == -1)
        return INF;
    if (treap[treap[p].l].size >= rank)
        return GetValByRank(treap[p].l, rank);
    if (treap[treap[p].l].size + treap[p].cnt >= rank)
        return treap[p].val;
    return GetValByRank(treap[p].r, rank-treap[treap[p].l].size-treap[p].cnt);


int GetPre(int val)

    int ans = 1;//treap[1].val = -INF
    int p = root;
    while (p != -1)
    
        if (val == treap[p].val)
        
            if (treap[p].l != -1)
            
                p = treap[p].l;
                while (treap[p].r != -1)//在左子树上一直往右走
                    p = treap[p].r;
                ans = p;
            
            break;
        
        if (treap[p].val < val && treap[p].val > treap[ans].val)
            ans = p;
        if (val < treap[p].val)
            p = treap[p].l;
        else
            p = treap[p].r;
    
    return treap[ans].val;


int GetNext(int val)

    int ans = 2;//treap[2].val = INF
    int p = root;
    while (p != -1)
    
        if (treap[p].val == val)
        
            if (treap[p].r != -1)
            
                p = treap[p].r;
                while (treap[p].l != -1)
                    p = treap[p].l;
                ans = p;
            
            break;
        
        if (treap[p].val > val && treap[p].val < treap[ans].val)
            ans = p;
        if (val < treap[p].val)
            p = treap[p].l;
        else
            p = treap[p].r;
    
    return treap[ans].val;


int main()

    Build();
    scanf("%d", &n);
    int opt, val;
    while (n--)
    
        scanf("%d%d", &opt, &val);
        switch (opt)
        
            case 1:
                Insert(root, val);
                break;
            case 2:
                Remove(root, val);
                break;
            case 3:
                printf("%d\n", GetRankByVal(root, val)-1);
                break;
            case 4:
                printf("%d\n", GetValByRank(root, val+1));
                break;
            case 5:
                printf("%d\n", GetPre(val));
                break;
            case 6:
                printf("%d\n", GetNext(val));
                break;
        
    

    return 0;

以上是关于平衡树的主要内容,如果未能解决你的问题,请参考以下文章

平衡树的简介

解密树的平衡:二分搜索树 → AVL自平衡树 → 左倾红黑树

解密树的平衡:二分搜索树 → AVL自平衡树 → 左倾红黑树

解密树的平衡:二分搜索树 → AVL自平衡树 → 红黑树

平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板超详解

树总结(二)平衡二叉树