堆的进化之旅5-Relaxed Heap松弛堆
文章目录
- Rank Relaxed Heap
- Pair transformation
- Clean
- Active sibling transformation
- Good sibling transformation
- Run Relaxed Heap
- Singleton transformation
- (1)
- (2.1)
- (2.2)
- (3)
- Run transformation
- (1)
- (2)
- 尾声
堆的进化之旅的分支——松弛堆。
为记录算法研讨课精彩报告而生。
1987年,Michael L. Fredman 与 Robert E. Tarjan志得意满地公开发表了斐波那契堆,分操作复杂度都优化到了那时也是现在为止最好的程度:两个O(1)加1个O(log n)。他们满心以为已经到达了堆进化之旅的尽头,但可惜在这趟旅途的终点已经被Driscoll·Gabow占据。1988年,前后脚,Driscoll·Gabow发表了松弛堆,复杂度分析上与斐波那契堆处于同一水平,但他的常数项却小于斐波堆。接下来几年中,原本为推广斐波那契堆的时间,却屡屡让松弛堆出尽风头。那什么是松弛堆呢?
松弛堆
Operation | Linked List | Binary Heap | Binomial Heap | Fibonaaci Heap | Relaxed Heap |
---|---|---|---|---|---|
Push | O(1) | O(log n) | O(1) amortized | O(1) amortized | O(1) amortized |
Pop_min | O(n) | O(log n) | O(log n) | O(log n) amortized | O(log n) amortized |
Decrease_key | O(1) | O(log n) | O(log n) | O(1) amortized | O(1) amortized |
创造一个标记:好节点或坏节点。
如果一个节点是根节点或者符合堆有序(比父亲节点要大),那么就是好节点,否则是坏节点。
还有active(活跃)标记,简单地说,在更新关键字之后呢,它有可能不符合堆有序了,是潜在的威胁,那么我们把它标记为活跃节点,意思是说,注意这个嫌疑犯,别让它干坏事,这样看来和坏小子bad node又有区别,但实际上我们姑且认为它们是一样的。
同时有结论:所有坏节点都是活跃节点。
为介绍具体操作,我们创造4种标记符号,
- 孩子是好的,那么标记上指向父亲的箭头;
- 孩子是新产生的活跃节点,那么把与父亲连接的边画成虚线;
- 如果孩子的状态未知,就什么也不做;
- 孩子是活跃的坏节点,即不满足堆特性,标记上叉;
就其具体操作来说,可以把松弛堆分为两类,我们首先来看Rank松弛堆,它的定义有两项,即对每一个数字 r 来说,有r 个孩子的节点最多有 1 个active 顶点,并且对每一个active顶点,都是最后一个孩子。为了满足这个定义,当出现一些不符合的情况时,我们可以执行四种操作,将其转化为Rank松弛堆,分别是pair transformation,也就是针对一对相同堆的操作;clean,也就是清理操作;active sibling transform,针对两个活跃节点的操作;good sibling transform,针对其相邻节点是好节点的情况。
Rank Relaxed Heap
Pair transformation
Clean
接下来是clean清理操作,因为从图中我们可以看出活跃节点x并没有如定义里指出那样是最后一个节点,这时我们就可以找到它的最后一个兄弟节点q’的最后一个儿子节点,然后将他们进行交换,实现将活跃节点变成最后一个节点的要求,这里我们也只是进行了1个交换操作,因此时间复杂度也为O(1)
Active sibling transformation
第三个是active sibling transformation操作,此操作针对有两个活跃节点的情况,他们是兄弟节点,且有r个孩子的节点a位于倒数第二个孩子节点位置,有r+1个孩子节点的s节点位于最后一个孩子节点的位置,这也是不符合定义要求的,因为定义要求是每棵树只准有一个活跃的子节点,为了调整,我们将以p,a,s为根节点的子树拆下,在这里我们注意到一个细节,因为a是坏节点,所以a的键值大于p的键值,因此将a子树和p子树进行合并,因为都有r个孩子,并且a当父亲节点,因为a的键值比较小。合并a和p后,a和s都是有r+1个孩子的节点,因此我们就可以仿照之前的操作,将a和s合并,选取他们两个中较小的作为父节点c,连接到节点g下,同样的,因为是新产生的活跃节点,因此我们以虚线连接c和g,这都是O(1)操作,复杂度为O(1)
Good sibling transformation
最后是good sibling transformation操作,顾名思义,因为活跃节点a的兄弟节点s是好节点,这里可以分两种情况来讨论,(1)若s节点的最后一个孩子节点c是坏节点,那么就将a和c拆下,并仿照上述操作,将其合并为有r+1个孩子节点的c,这时,p和s节点的组合使得p也有r+1个孩子,因此p和c也可进行合并(2)若s节点的最后一个孩子节点是好节点,其实对这个情况我们并不陌生,即刚刚展示的clean操作,最终可以看出这一步操作仍为常数步,时间复杂度为O(1)
Run Relaxed Heap
在松弛堆中另一类是Run松弛堆,它满足两个条件:活跃点数目,二项式树的个数,因此为了保证堆为Run松弛堆,操作可分成Singleton transformation操作和Run transformation这里强调两个概念, singleton 是不在一个运行里面的一个单独的活动节点,run是一个活跃的兄弟序列。下面我们来看具体操作:
Singleton transformation
(1)
Singleton transformation有3种情况,我们先来看第一种,PPT中这张图是不是很眼熟,没错,和pair transformation相同,只不过现在是以单个活跃节点的角度来进行操作,而pair transformation是以子树的角度来来进行操作,类似的,最终复杂度为O(1)。
我们这里采用了一个很重要的思想来讲解,类似于NP完全问题的证明,想办法把待证明的问题归约到已经证明的问题上即可,在这里我们想办法把所有情况转换成为(1)来求解。
(2.1)
第二种情况又根据c是否为好的节点分为两种,若c是a的兄弟节点s的最后一个节点并且是坏节点,观察图,这个情况和之前的pair transformation类似,我们可以将c当作pair transformation中的a节点,这样,这种情况就和pair transformation十分类似了,我们只需按照类似于pair transformation中对a和a’的操作来对c和a’进行类似的操作即可,时间复杂度依然为O(1)
左图中用灰色铅笔圈出的p, s, c部分,把它看作(1)里面左边的g, p, a即可。于是问题转化为(1)。
(2.2)
若c是a的兄弟节点s的最后一个节点并且是好节点,正如图片上部所示的图,我们发现和clean操作类似,因此我们进行类似于clean的操作,将a和c进行互换即可,最后所需复杂度和clean操作相同,为O(1)
这样我们就把问题转化成为了(2.1)
(3)
下面是Singleton transformation的第三种情况,这时,a和a’都是活跃节点且不为最后一个孩子,我们可就c和c’是否是好的节点进行分类,两两组合就会有4种情况。(我们首先来看c和c’都是好的的情况,没错,这时两棵子树的情况和clean的操作都类似,我们可以对两棵树分别进行clean操作;再来看c和c’一好一坏的情况,这种情况我们也是十分的熟悉,就和Singleton transformation的2.1操作类似,如灰色的圈所示,我们可以将其看作2.1中那颗较小的子树,从而执行类似于2.1的操作;对于c和c’都是坏节点的情况,相信大家已经找到了规律,)最后发现这就是2.2的情况的进阶版,
还可以把步子迈小一点,以左边2个图为例,下部用灰色铅笔全出的部分看作是(2)里面的右边就好,这样将问题转化为(2),具体对应关系呢
(c, c’) | good, good | good, bad | bad, good | bad, bad |
---|---|---|---|---|
transform | a<->c, a’<->c’ | 2.2 | 2.2 | 2.1 |
Run transformation
(1)
接下来是Run transformation,就a是否为最后一个节点来分情况讨论。在这里,我们先讨论a是最后一个节点的情况,看到有r-1个节点的p和t,自然而然想到将她们两个进行合并,形成有r个节点的树,从t是坏节点也可以看出,p比t大,因此合并时我们以t为父亲,之后,两个均有r个节点的t和a就可以进行合并操作,选取他们中较小的一个为父节点,连接至g下,同样的,是新生成的活跃节点,所以连线为虚线。
(2)
然后是第二种情况,a不是最后一个节点的情况,这时我们将p的所有子节点拆下后,可以看出,c和p都有r-1个子节点,先将他们进行合并,形成有根节点度为r的树,再与d合并,形成有r+1个孩子节点的树。再将t和s节点合并,形成有r个孩子节点的树,然后再与a节点合并,形成有r+1个孩子节点的树,取t和a中较小的为父节点,然后就可以与同为r+1个孩子的节点p进行合并,从而完成操作,使得活跃节点到最后一个。
还可以这么看,对于顶点p来说,t和a是坏孩子,s是好孩子,它们之间的大小关系一目了然,这样先合并t和s,再将合并之后的t与a合并,去较小者为新父亲节点,连在p的后面,至于c和d,可以看作是打酱油的存在。
至此,所有操作都已介绍完成,松弛堆复杂就复杂在针对多种不同的情况进行优化处理,写成伪代码就如图中,最终复杂的算法步骤产生了简单的时间复杂性。
翻译成一个流程图
在堆的进化之旅尽头,我们根据论文复现了这几种数据结构,它们应用在迪杰斯特拉算法中获得的效率就如这四幅图所示,结果恰如之前分析,Relaxed Heap 和 Fibonacci Heap效率最高。
尾声
我们合并的时候,总是对度数相等的树来下手。这一系列所有堆都是这样,这也对应了Fibonacci 数列的经典公式 f(i) = f(i-1) + f(i-2)
堆的进化之旅5-Relaxed Heap松弛堆相关推荐
- pwn with glibc heap(堆利用手册)
前言 对一些有趣的堆相关的漏洞的利用做一个记录,如有差错,请见谅. 文中未做说明 均是指 glibc 2.23 相关引用已在文中进行了标注,如有遗漏,请提醒. 简单源码分析 本节只是简 ...
- 【云栖大会】与马云一起开启“飞天·进化”之旅
与马云一起开启"飞天·进化"之旅 再过20个小时,2016杭州云栖大会就要开幕了,我们的倒计时海报也陪伴大家走过了16个日夜.相信大家会对这次大会主题"飞天·进化&quo ...
- PMP认证与企业项目管理的进化之旅
PMP发展历史 随着时间的推移,PMP认证不断演进,与之相应的,企业项目管理环境也发生了巨大的变化.让我们回顾一下每个版本的发布时间,并探索在相应的时期内企业项目管理中发生的变化. PMP 1st E ...
- Button 的 进化之旅 | 我们是如何设计 Compose API 的 (下篇)
本文由 Jetpack Compose 团队的 Louis Pullen-Freilich (软件工程师).Matvei Malkov (软件工程师) 和 Preethi Srinivas (UX 研 ...
- Button的“进化之旅”
/ 今日科技快讯 / 近日,从微软卸任后,前微软副总裁.微软全球卓越工程师姚麒今日回归小冰团队.2006年,姚麒回到北京,成为微软(亚洲)互联网工程院(STCA)的缔造者之一.2015年到20 ...
- python:实现skew heap倾斜堆算法(附完整源码)
python:实现skew heap倾斜堆算法 from __future__ import annotationsfrom collections.abc import Iterable, Iter ...
- “扬帆起航 开启DHR新纪元” 中建信息携手SAP SuccessFactors 人力资源“进化”之旅...
申耀的科技观察 读懂科技,赢取未来! 7月19日,中建信息携手SAP,在天府之国成都引领合作伙伴开启了一场SAP SuccessFactors 人力资源'进化'之旅".SAP Success ...
- java 堆和栈 数据结构_数据结构的栈和堆和程序中的堆和栈
在计算机领域,堆栈是一个不容忽视的概念,我们编写的C语言程序基本上都要用到.但对于很多的初学着来说,堆栈是一个很模糊的概念.堆栈:一种数据结构.一个在程序运行时用于存放的地方,这可能是很多初学者的认识 ...
- java 浅堆 深堆_JVM中的一个小知识点:深堆和浅堆的概念
java中的堆内存算是整个内存区域中最重要的一块,几乎所有的对象都分配在堆内存.在堆内存中有两个主要的概念需要我们理解,这对分析java堆内存的故障有着重要的作用,分别是深堆和浅堆. 一.概念 我们先 ...
- python树结构实现小顶堆_数据结构和算法入门之小顶堆和大顶堆Python实现
首先简单提一下小顶堆和大顶堆,其本质是一颗完全二叉树,不同点在于:除叶子节点外,小顶堆的每个父节点的key都要比其左右两个子节点的key小:大顶堆的每个父节点的key都要比其左右两个子节点的key大. ...
最新文章
- jquery中的attr()和prop()
- 插入数据,已存在则不插入
- 利用Vagrant and VirtualBox搭建core os环境
- 什么是事件冒泡?如何用jquery/js阻止事件冒泡?阻止冒泡有什么作用?小生来抛个砖。...
- 自由、开源及其敌人 —— RMS事件簿
- CentOS系统安装Java
- struts2.3+spring3.2+hibernate4.2例子
- 55. Attribute name 属性
- windows电脑借助多开软件实现ZALO程序多开
- 锐起无盘找不到服务器,锐起无盘出现重启后连接不到服务器
- 天猫八大策略人群京东十大靶向人群简介
- C语言 java 判断闰年,一个月有多少天
- R可视化会出现的问题1
- java语言简介论文,基于Java的Web论坛开发.doc
- pdfminer __init__() got an unexpected keyword argument ‘codec‘解决方案
- 中国空气质量AQI热力图
- 【学术信息】2019年期刊中科院分区-环境科学与生态学
- ios 输入法扩展_iOS 11自带输入法新增3个小功能,贴心!
- windows7 系统搭建webdav服务
- Redis项目应用场景与实例(三):队列(List)
热门文章
- Range Coder编码比特流
- java的fprintf_fprintf不接受一个字符数组吗?
- idea 关闭检查更新_intellij idea怎么关闭自动更新
- roc曲线spss怎么做_统计第十三课:SPSS ROC曲线
- 创建室内导航地图的9个步骤
- 《java语言程序设计》泽勒一致性问题
- 心理学与生活《感知与记忆》
- C++内存分配(operator new)
- python打包时出现RecursionError: maximum recursion depth exceeded的解决方法
- 二进制转化成ascll_怎样将二进制转ascii码