平衡树(Treap)的基本操作

2024-03-15 12:18
文章标签 基本操作 平衡 treap

本文主要是介绍平衡树(Treap)的基本操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

例题1:

这是一道模板题,你需要实现一个 multiset 的基本操作。具体如下:

  1. 插入一个数 x;

  2. 删除一个数 x(保证这个数一定存在);

  3. 查询一个数 x 是否存在。

利用数组实现

#include<bits/stdc++.h>
using namespace std;
const int maxn=3*1e5+5;
struct edge{int ls,rs,fix,num;
};
struct node{edge tree[maxn];int root,len=0;node(){root=0;} bool check(int now,int v){if(now==0)return false; if(tree[now].num==v)return true;if(tree[now].num<v)return check(tree[now].rs,v);if(tree[now].num>v)return check(tree[now].ls,v);}void turn_R(int &now){int tmp=tree[now].ls;tree[now].ls=tree[tmp].rs;tree[tmp].rs=now;now=tmp;}void turn_L(int &now){int tmp=tree[now].rs;tree[now].rs=tree[tmp].ls;tree[tmp].ls=now;now=tmp;}void insert(int &now,int v){if(now==0){tree[++len]={0,0,rand(),v};now=len;return ;}else if(tree[now].num>=v){insert(tree[now].ls,v);if(tree[tree[now].ls].fix<tree[now].fix)turn_R(now);}else if(tree[now].num<v){insert(tree[now].rs,v);if(tree[tree[now].rs].fix<tree[now].fix)turn_L(now);}}void remove(int &now,int v){if(now==0)return ;if(tree[now].num==v){if(tree[now].ls==0||tree[now].rs==0){if(tree[now].rs)now=tree[now].rs;else now=tree[now].ls;}else if(tree[tree[now].ls].fix<tree[tree[now].rs].fix){turn_R(now);remove(tree[now].rs,v);}else {turn_L(now);remove(tree[now].ls,v);}}else if(tree[now].num<v){remove(tree[now].rs,v);}else if(tree[now].num>v){remove(tree[now].ls,v);}}
}T;
int n,x,y;
int main()
{scanf("%d",&n);while(n--){scanf("%d%d",&x,&y);if(x==1)T.insert(T.root,y);if(x==2)T.remove(T.root,y);if(x==3)printf("%d\n",T.check(T.root,y));}return 0;
}

利用指针实现

#include<bits/stdc++.h>
using namespace std;
struct edge{int num,fix;edge *ls,*rs;edge(int v){num=v;fix=rand();ls=NULL;rs=NULL;}
};
struct node{edge *root=NULL;void turn_R(edge *&now){edge *tmp=now->ls;now->ls=tmp->rs;tmp->rs=now;now=tmp;}void turn_L(edge *&now){edge *tmp=now->rs;now->rs=tmp->ls;tmp->ls=now;now=tmp;}bool check(edge *now,int v){if(now==NULL)return false;if(now->num==v)return true;if(now->num<v)return check(now->rs,v);if(now->num>v)return check(now->ls,v);}void insert(edge *&now,int v){if(now==NULL){now= new edge(v);return ;}if(now->num<=v){insert(now->rs,v);if(now->rs->fix<now->fix)turn_L(now);}else if(now->num>v){insert(now->ls,v);if(now->ls->fix<now->fix)turn_R(now);}return ;}void remove(edge *&now,int v){if(now->num==v){if(now->ls==NULL||now->rs==NULL){edge *tmp=now;if(now->ls)now=now->ls;else now=now->rs;delete tmp;}else if(now->ls->fix<now->rs->fix){turn_R(now);remove(now->rs,v);}else{turn_L(now);remove(now->ls,v);}}else if(now->num<v)remove(now->rs,v);else remove(now->ls,v);return ;}
}T;
int n,x,y;
int main()
{scanf("%d",&n);while(n--){scanf("%d%d",&x,&y);if(x==1)T.insert(T.root,y);if(x==2)T.remove(T.root,y);if(x==3)printf("%d\n",T.check(T.root,y));}return 0;
}

容易出错的点:

  1. root没有初始化
  2. 进行删除操作时用if可能会导致树满足第一个条件后进行删除,删除后又满足第二个条件,应用else if
  3. 操作时没有修改root的值

例题2:

        【模板】普通平衡树 - 洛谷

Treap实现

#include<bits/stdc++.h>
using namespace std;
struct edge{int num,fix,size,weight;edge *ls,*rs;edge(int v){num=v;fix=rand();size=1;weight=1;ls=NULL;rs=NULL;}int lsize(){return ls?ls->size:0;}int rsize(){return rs?rs->size:0;}
};
struct treap{edge *root=NULL;void update(edge *now){if(now)now->size=now->lsize()+now->rsize()+now->weight;return ;}void LeftRotate(edge *&now){
//		cout<<"turn left\n";edge *tmp=now->rs;now->rs=tmp->ls;tmp->ls=now;now=tmp;update(now->ls);update(now);return ;}void RightRotate(edge *&now){
//		cout<<"turn right\n";edge *tmp=now->ls;now->ls=tmp->rs;tmp->rs=now;now=tmp;update(now->rs);update(now);return ;}void insert(edge *&now,int v){if(!now){now= new edge(v);}else if(now->num==v){now->size++;now->weight++;}else if(now->num>v){insert(now->ls,v);if(now->ls->fix<now->fix)RightRotate(now);}else {insert(now->rs,v);if(now->rs->fix<now->fix)LeftRotate(now);}update(now);return ;}void remove(edge *&now,int v){if(!now)return ;if(now->num==v){if(now->weight>1){now->weight--;now->size--;}else if(now->ls==NULL||now->rs==NULL){
//				cout<<"start\n";edge *tmp=now;if(now->ls)now=now->ls;//这里不能写成RightRotate(now)else now=now->rs;delete tmp;
//				cout<<"out\n";}else if(now->ls->fix<now->rs->fix){RightRotate(now);remove(now->rs,v);}else {LeftRotate(now);remove(now->ls,v);}}else if(now->num<v){remove(now->rs,v);}else {remove(now->ls,v);}update(now);return;}int find_x(edge *now,int v,int rank){//查询 x数的排名(排名定义为比当前数小的数的个数 +1 )if(now->num==v)return now->lsize()+rank+1;else if(now->num>v)return find_x(now->ls,v,rank);else return find_x(now->rs,v,rank+now->lsize()+now->weight);}edge *find_pos_x(edge *now,int rank){//查询排名为 x 的数if(!now)return NULL;else if(now->lsize()>=rank)return find_pos_x(now->ls,rank);else if(now->lsize()+now->weight>=rank)return now;else return find_pos_x(now->rs,rank-now->lsize()-now->weight);}edge *find_biggest(edge *now,int v,edge *last){if(!now)return last;else if(now->num<v)return find_biggest(now->rs,v,now);else return find_biggest(now->ls,v,last);}edge *find_smallest(edge *now,int v,edge *last){if(!now)return last;else if(now->num>v)return find_smallest(now->ls,v,now);else return find_smallest(now->rs,v,last);}bool find_have(edge *now,int v){if(!now)return false;else if(now->num==v)return true;else if(now->num<v)return find_have(now->rs,v);else return find_have(now->ls,v);}
}T;
int n,x,y;
int main()
{scanf("%d",&n);while(n--){scanf("%d%d",&x,&y);if(x==1)T.insert(T.root,y);if(x==2)T.remove(T.root,y);if(x==3)printf("%d\n",T.find_x(T.root,y,0));if(x==4)printf("%d\n",T.find_pos_x(T.root,y)->num);if(x==5)printf("%d\n",T.find_biggest(T.root,y,NULL)->num);if(x==6)printf("%d\n",T.find_smallest(T.root,y,NULL)->num);if(x==7)printf("%d\n",T.find_have(T.root,y));}return 0;
}

可能出错的点:

  1. 判断时最后一个使用else if 容易漏条件,最好改成else
  2. 查询时不要漏了return
  3. 进行删除操作时绝对不能旋转去删除
  4. update函数要判断当前节点是否为NULL

这篇关于平衡树(Treap)的基本操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/811960

相关文章

MongoDB学习—(3)shell的基本操作

一,删除数据库中的集合文档 命令为 db.[documentName].drop() 二,删除数据库 命令为 db.dropDatabase() 执行该命令时,应该先进入想要删除的数据库中,如 三,shell中的help 我们可以运用shell中的help来查询相关的操作,查询数据库相关的就用db.help(),查询集合相关的就用db.[documentName].help

MongoDB学习—(2)shell的基本操作

一,创建一个数据库 使用use关键字,格式为 use [databasename] 当你这样创建一个数据库时,该数据库只是创建于内存中,只有你对数据库执行一些操作后,数据库才真正的创建,否则如果直接关掉mongodb,数据库在内存中会被删除掉。 二,查看所有数据库 命令为 show dbs Mysql中的命令为show databases,两者有所不同。 三,查看数据库中的现有的文

带头结点的线性链表的基本操作

持续了好久,终于有了这篇博客,链表的操作需要借助图像模型进行反复学习,这里尽可能的整理并记录下自己的思考,以备后面复习,和大家分享。需要说明的是,我们从实际应用角度出发重新定义了线性表。 一. 定义 从上一篇文章可以看到,由于链表在空间的合理利用上和插入、删除时不需要移动等优点,因此在很多场合下,它是线性表的首选存储结构。然而,它也存在某些实现的缺点,如求线性表的长度时不如顺序存储结构的

【自动驾驶】控制算法(八)横向控制Ⅱ | Carsim 与 Matlab 联合仿真基本操作

写在前面: 🌟 欢迎光临 清流君 的博客小天地,这里是我分享技术与心得的温馨角落。📝 个人主页:清流君_CSDN博客,期待与您一同探索 移动机器人 领域的无限可能。 🔍 本文系 清流君 原创之作,荣幸在CSDN首发🐒 若您觉得内容有价值,还请评论告知一声,以便更多人受益。 转载请注明出处,尊重原创,从我做起。 👍 点赞、评论、收藏,三连走一波,让我们一起养成好习惯😜 在这里,您将

FHQ Treap模版(luogu P3369)

FHQ Treap模版(自用),带注释 #include<bits/stdc++.h>using namespace std;const int N=1e5+10;int n,root,idx;struct node{int l,r;int val,key,size;}tr[N];int getnew(int v){tr[++idx].val=v;//权值tr[idx].key=rand(

写给大数据开发:你真的“慢“了吗?揭秘技术与职场的平衡艺术

你是否曾经在深夜里,面对着一个棘手的数据处理问题,感到无比沮丧?或者在一次重要的项目汇报中,突然语塞,无法清晰地表达你的技术方案?作为一名大数据开发者,这些场景可能再熟悉不过。但别担心,因为你并不孤单。让我们一起探讨如何在这个瞬息万变的行业中,既磨练技术利刃,又培养职场软实力。 目录 技术与时间的赛跑1. 长远视角的重要性2. 复利效应在技能学习中的应用 跨界思维:数据结构教我们的职场智

Github基本操作【学习笔记】

Set Up Git 配置全局用户名 git config --global user.name "Your Name Here" 配置全局邮箱 git config --global user.email "your_email@example.com" 配置全局邮箱 Create A Repo More about repositories Click

代码随想录 -- 二叉树 -- 平衡二叉树

110. 平衡二叉树 - 力扣(LeetCode) 思路:仍然是递归调用 1. 定义一个递归函数 count 用来计算二叉树的层数 2. isBalanced 函数:如果传入根节点为空返回真;如果根节点 | 左子树的层数 - 右子树的层数 | 大于1,返回假;最后返回根节点左子树、右子树是否是平衡二叉树。 class Solution(object):def count(self,root

git:认识git和基本操作(1)

目录 一、版本控制器 1.安装git 2.创建git本地仓库 3.配置git 二、git操作(1) 1.工作区、暂存区、版本库 2.添加文件 3.查看.git 4.修改文件 一、版本控制器         所谓的版本控制器,就是能让你了解到每一个文件的修改历史。相应的,在企业级开发中,用来记录一个工程的每一次改动和管理版本迭代,同时方便多人协作开发。         g

6.2图的存储及基本操作

6.2.1顺序存储 邻接矩阵法,用一个一维数组存储图中顶点信息,二维数组存储图中边的信息 无向图 1.无向图的邻接矩阵关于对角线对称,可采用压缩存储 2.边数为e,则邻接矩阵中1为2e; 3.第i行or 第i列非零元素之和恰好为顶点i的度数 4.判断是否有边用0,1 5. 有向图 1.关于对角线不对称 2.行表示入度,列表示出度,行+列表示该顶点的度 6.2.2链式存储