平衡树Treap

在学习平衡树Treap之前,我们先来了解什么是二叉查找树。

二叉查找树(BST:Binary Search Tree)

一棵二叉查找树定义如下:

1、树中每个节点都有一个权值。(现假设权值均不相同)

2、若左子树非空,则左子树上所有节点的权值均小于根节点的权值。

3、若右子树非空,则右子树上所有节点的权值均大于根节点的权值。

4、左右子树也分别为二叉查找树。

如下图所示,树中每个节点中的数字代表的节点权值,显然,下图是一棵二叉查找树。

可以观察到,一棵BST的中序遍历是一个升序序列。(如果不存在重复值的话)

给定一个序列A,我们可以建立一棵BST方便地实现查询、插入、删除操作。如果序列A有n个元素,且对应的BST的高度为logn,那么每次查询、插入、删除操作复杂度自然是logn的。(BST的插入、删除、查询算法这里省略,较简单,请自行补充学习)。

但是我们也会发现,有时候序列A的数据会导致所建立的BST退化为链,或高度远大于logn。这时的查询等操作复杂度就变得很高。例如序列A=[1,2,3,4,5,6].我们可以建立一棵对应的BST如下图所示:

但我们发现,序列A不是只有一棵BST,下图的3种也可以称为序列A对应的BST。并且下图每一个BST的中序遍历和图2都是一致的。

我们称中序遍历一样的两棵BST是等价BST。

并且我们发现下面两棵等价BST可以通过一次旋转得到。例如下图:

左边BST可通过左旋以4为根的子树得到右边的BST,反之亦然。

Zig(右旋)/  Zag(左旋)

我们定义两种操作Zig(右旋)和  Zag(左旋)如下:

Zig

对于以v为根的子树进行Zig(右旋)操作,步骤如下:

(1)假设v的左二子为c,调整v的左二子为c的右儿子。

(2)调整c的右儿子为v。

(3)调整根v为c。

Zig参考代码
Zag

对于以v为根的子树进行Zag(左旋)操作,步骤如下:

(1)假设v的右二子为c,调整v的右二子为c的左儿子。

(2)调整c的左儿子为v。

(3)调整根v为c。

Zag参考代码

平衡树Treap

根据上面的分析,当序列的数字有序时,序列极有可能退化为链,树上操作复杂度会变得很高,于是我们需要设法调整BST的高度。根据不同的调整策略,对应了不同的平衡树类型,例如Treap,AVL,Splay,红黑树等等。

Treap的基本思想是,对于随机数据,序列所构造的BST的高度期望值 为logn。

在实际操作时,Treap对BST上的每个节点除了维护基本信息(左右儿子编号l,r,权值w,子树数字个数size,重复元素计数cnt等信息以外),额外维护一个随机优先级pri。如下:

树上节点信息

并且我们规定,树上所有节点的Pri值必须满足小根堆性质。即,每个节点的pri值小于左右儿子的pri值。如下图:

节点中数字代表权值w,节点旁数字代表pri

那么,在Treap中插入或删除一个节点时,会导致Treap的Pri值不满足小根堆性质,根据上面提及的等价BST概念,我们可以通过Zig或Zag操作来进行调整。具体方式如下:

Treap插入操作

1.插入节点算法步骤

Step1、u从根节点r开始,如果x<r.w,递归插入左子树;否则递归插入右子树。

Step2、如果当前节点为空,在此节点建立新的节点即可。

Step3、为新建立的节点随机分配优先级,回溯时检查优先级是否满足堆序。

       Step 3.1 若左子节点优先级小于当前节点,右旋。

        Step 3.2 若右子节点优先级小于当前节点,左旋。

2.插入节点示例

现在,如果要在Treap中插入一个新的节点,例如(w=4,pri=15)。

插入新节点(w=4,pri=15)

发现现在的Treap不满足pri值的小根堆性质了,并且对于节点3这棵子树来讲,其右儿子节点4的pri值小于3的pri值,此时,我们可以将3这棵子树左旋,如下图:

现在的Treap仍然不满足pri值的小根堆性质,并且对于节点5这棵子树来讲,其左二子节点4的pri值小于节点5的pri值,此时,我们可以将5这棵子树右旋,如下图:

至此,经过旋转操作的Treap已经满足要求。下图为参考代码:

插入节点操作参考代码

说明:这个参考代码里面,对于重复元素的处理是维护的节点的cnt信息。

Treap删除操作

1.删除节点算法步骤

Step1、如果当前节点是叶子节点,或只有一个子节点的非叶子节点。直接删除即可,用它的孩子节点替换它。

Step2、如果当前节点是有2个子节点的非叶子节点。通过旋转操作将其变为可以直接删除的节点。

        Step2.1、如果该节点的左孩子优先级<右孩子优先级,右旋该节点;

        Step2.2、否则左旋该节点。转Step2.

2.删除节点示例

例如,现在要删除节点8,对于节点8而言,其右儿子pri值小于左二子pri值,那么左旋8为根的子树。

左旋8

此时节点8已经是一个可以直接删除的节点,用8的左二子替换它即可。

删除8
删除节点参考代码

Treap的用途

1、查询数x的排名。算法如下:

(1)设结果为ans,初始ans=0.

(2)从根节点num开始,如果x==t[num].w,答案即为t[t[num].l].size+ans+1;如果x<t[num].w,递归查询左子树;如果x>r.w,更新ans+=t[t[num].l].size+t[num].cnt,递归查询右子树。

查询x的排名参考代码

2、查询数x的前驱或后继。注意区分是严格前驱(后继)还是非严格前驱(后继)。

非严格前驱(后继)定义:x的前驱定义为Treap中不大于x的最大值。后继定义为不小于x的最小值。

算法如下:

(1)设结果为ans,初始ans=0.

(2)从根节点num开始,如果x>=t[num].w,更新ans为当前节点,递归查询右子树;如果x<t[num].w,递归查询左子树。如果当前节点为空,ans即为答案。

查询非严格前驱(后继)参考代码
查询非严格前驱(后继)参考 代码

3、查询序列中的第K大或第K小。算法如下:

由于Treap每个节点维护了size信息,从根节点num开始:

(1)如果k<=t[t[num].l].size,那么递归查询左子树第k大。

(2)否则如果t[t[num].l].size<k<=t[t[num].l].size+t[num].cnt,根节点值即为所求.

(3)否则递归查询右子树第k-t[t[num].l].size-t[num].cnt大。

查询第k小参考代码

二分查找、平衡树、权值线段树的对比

习题

ybt1565-1568

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容