博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Treap
阅读量:2441 次
发布时间:2019-05-10

本文共 4203 字,大约阅读时间需要 14 分钟。

Treap

         Treap=Tree+Heap,Treap是一个二叉搜索树,它的左右子树都分别是一个Treap,和一般二叉排序树不同的是,Treap记录一个额外的数据(v),就是优先级(rank)。Treap在以关键字构成二叉排序树的同时,还满足堆的性质,不过Treap不一定是完全二叉树,而堆必须是完全二叉树.

 

1.结构体定义:

struct data{

         int l,r;  //左右子树

int v;  //当前节点的值

int size; //由该节点为根构成的子树的大小

int rnd; //当前节点的优先级

int w; //和当前节点值相同的个数

}tr[MAXN];

 

2.Treap的性质:

(1)    如果b是a的左子树,那么tree[a].v>tree[b].v;

(2)    如果c是a的右子树,那么tree[a].v<tree[c].v;

(3)    如果b,c分别是a的左右子树,那么tree[a].rank<tree[b].rank&& tree[a].rank<tree[c].rank;

 

3.Treap的旋转:跟普通的旋转一样

代码实现:

void update(int k)//更新结点信息

{

         tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w;

}

void rturn(int &k)

{

         int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;

         tr[t].size=tr[k].size;update(k);k=t;

}

void lturn(int &k)

{

         int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;

         tr[t].size=tr[k].size;update(k);k=t;

}

 

4.Treap的插入:

(1)按照二叉树的插入方法,将结点插入到树中

(2)根据堆的性质(我们这里为最小堆)和优先级的大小调整结点位置。

代码实现:

void insert(int &k,int x){

         if(k==0){

                   size++;k=size;

                   tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand();

                   return;

         }

         tr[k].size++;

    if(tr[k].v==x)tr[k].w++;

         else if(x>tr[k].v){

                   insert(tr[k].r,x);

                   if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k); //维护堆性质

         }

         else {

                   insert(tr[k].l,x);

                   if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);

         }

}

 

5.Treap的删除:

(1)利用二叉树的性质,找到和x值相同的节点

(2)如果和x值相同的节点的个数有多个,那么只需要将size和w减一即可

(3)如果和x值相同的节点的个数只有一个,而且其存在一个子结点,那么当前需要删除的结点的值应该更新为存在的子节点的值,如果存在两个子结点,那么判断两个子结点的优先级,优先级值小的被更新为删除结点的值。

代码实现:

void del(int &k,int x){

    if(k==0)return;

         if(tr[k].v==x){

                   if(tr[k].w>1){

                            tr[k].w--;tr[k].size--;return;//若不止相同值的个数有多个,删去一个

                   }

                   if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;//有一个儿子为空

                   else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd)

                            rturn(k),del(k,x);

                   else lturn(k),del(k,x);

         }

         else if(x>tr[k].v)

                   tr[k].size--,del(tr[k].r,x);

         else tr[k].size--,del(tr[k].l,x);

}

 

6.Treap的应用:

(1) 查询x数的排名(若有多个相同的数,因输出最小的排名)

代码实现:

int query_rank(int k,int x){

    if(k==0)return 0;

         if(tr[k].v==x)return tr[tr[k].l].size+1;

         else if(x>tr[k].v)

                   return tr[tr[k].l].size+tr[k].w+query_rank(tr[k].r,x);

         else return query_rank(tr[k].l,x);

}

(2) 查询排名为x的数

代码实现:

int query_num(int k,int x){

    if(k==0)return 0;

         if(x<=tr[tr[k].l].size)

                   return query_num(tr[k].l,x);

    else if(x>tr[tr[k].l].size+tr[k].w)

                   return query_num(tr[k].r,x-tr[tr[k].l].size-tr[k].w);

    else return tr[k].v;

}

(4)    求x的前驱(前驱定义为小于x,且最大的数)和x的后继(后继定义为大于x,且最小的数)

代码实现:

int ans=0;

void query_pro(int k,int x){  //前驱

    if(k==0)return;

    if(tr[k].v<x){

                   ans=k;query_pro(tr[k].r,x);

         }

    else query_pro(tr[k].l,x);

}

cout<<tree[ans].v<<endl;

void query_sub(int k,int x){  //后继

         if(k==0)return;

         if(tr[k].v>x){

                   ans=k;query_sub(tr[k].l,x);

         }

         else query_sub(tr[k].r,x);

}

cout<<tree[ans].v<<endl;

 

7.完整代码:

struct data{

         int l,r,v,size,rnd,w;

}tr[MAXN];

int n,size,root,ans;

void update(int k)//更新结点信息

{

         tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w;

}

void rturn(int &k)

{

         int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;

         tr[t].size=tr[k].size;update(k);k=t;

}

void lturn(int &k)

{

         int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;

         tr[t].size=tr[k].size;update(k);k=t;

}

void insert(int &k,int x)

{

         if(k==0)

         {

                   size++;k=size;

                   tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand();

                   return;

         }

         tr[k].size++;

    if(tr[k].v==x)tr[k].w++;//每个结点顺便记录下与该节点相同值的数的个数

         else if(x>tr[k].v)

         {

                   insert(tr[k].r,x);

                   if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);//维护堆性质

         }

         else

         {

                   insert(tr[k].l,x);

                   if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);

         }

}

void del(int &k,int x)

{

    if(k==0)return;

         if(tr[k].v==x)

         {

                   if(tr[k].w>1)

                   {

                            tr[k].w--;tr[k].size--;return;//若不止相同值的个数有多个,删去一个

                   }

                   if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;//有一个儿子为空

                   else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd)

                            rturn(k),del(k,x);

                   else lturn(k),del(k,x);

         }

         else if(x>tr[k].v)

                   tr[k].size--,del(tr[k].r,x);

         else tr[k].size--,del(tr[k].l,x);

}

int query_rank(int k,int x)

{

    if(k==0)return 0;

         if(tr[k].v==x)return tr[tr[k].l].size+1;

         else if(x>tr[k].v)

                   return tr[tr[k].l].size+tr[k].w+query_rank(tr[k].r,x);

         else return query_rank(tr[k].l,x);

}

int query_num(int k,int x)

{

    if(k==0)return 0;

         if(x<=tr[tr[k].l].size)

                   return query_num(tr[k].l,x);

    else if(x>tr[tr[k].l].size+tr[k].w)

                   return query_num(tr[k].r,x-tr[tr[k].l].size-tr[k].w);

    else return tr[k].v;

}

void query_pro(int k,int x)

{

    if(k==0)return;

    if(tr[k].v<x)

         {

                   ans=k;query_pro(tr[k].r,x);

         }

    else query_pro(tr[k].l,x);

}

void query_sub(int k,int x)

{

         if(k==0)return;

         if(tr[k].v>x)

         {

                   ans=k;query_sub(tr[k].l,x);

         }

         else query_sub(tr[k].r,x);

}

 

转载地址:http://vbbqb.baihongyu.com/

你可能感兴趣的文章
Installing Oracle9i 32-bit on Red Hat 9, 8.0, 7
查看>>
ORACLE面试题 一
查看>>
使用Opatch工具应用过渡性Patch
查看>>
ORACLE数据类型
查看>>
删除笔记本电脑EISA隐藏分区
查看>>
p3095277_9204_LINUX.zip
查看>>
Redhat Linux版本说明
查看>>
I cannot start the X server 问题的解决
查看>>
DBCA 创建库时到100%时停止不动。
查看>>
面对一个全新的环境,作为一个Oracle DBA,首先应该了解什么?
查看>>
DBMS_JOB包的用法 一
查看>>
AT命令详解 一
查看>>
数据库专题
查看>>
日期的各部分的常用的的写法
查看>>
xhost unable to open display解决方法
查看>>
面向 DBA 的 Linux Shell 脚本简介
查看>>
ORACLE体系结构总述
查看>>
使用Oracle的外部表查询警告日志文件
查看>>
EMCA常用命令
查看>>
linux wc命令
查看>>