文章目录

  • 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种标记符号,

  1. 孩子是好的,那么标记上指向父亲的箭头;
  2. 孩子是新产生的活跃节点,那么把与父亲连接的边画成虚线;
  3. 如果孩子的状态未知,就什么也不做;
  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松弛堆相关推荐

  1. pwn with glibc heap(堆利用手册)

    前言 ​ 对一些有趣的堆相关的漏洞的利用做一个记录,如有差错,请见谅. ​ 文中未做说明 均是指 glibc 2.23 ​ 相关引用已在文中进行了标注,如有遗漏,请提醒. 简单源码分析 ​ 本节只是简 ...

  2. 【云栖大会】与马云一起开启“飞天·进化”之旅

    与马云一起开启"飞天·进化"之旅 再过20个小时,2016杭州云栖大会就要开幕了,我们的倒计时海报也陪伴大家走过了16个日夜.相信大家会对这次大会主题"飞天·进化&quo ...

  3. PMP认证与企业项目管理的进化之旅

    PMP发展历史 随着时间的推移,PMP认证不断演进,与之相应的,企业项目管理环境也发生了巨大的变化.让我们回顾一下每个版本的发布时间,并探索在相应的时期内企业项目管理中发生的变化. PMP 1st E ...

  4. Button 的 进化之旅 | 我们是如何设计 Compose API 的 (下篇)

    本文由 Jetpack Compose 团队的 Louis Pullen-Freilich (软件工程师).Matvei Malkov (软件工程师) 和 Preethi Srinivas (UX 研 ...

  5. Button的“进化之旅”

    /   今日科技快讯   / 近日,从微软卸任后,前微软副总裁.微软全球卓越工程师姚麒今日回归小冰团队.2006年,姚麒回到北京,成为微软(亚洲)互联网工程院(STCA)的缔造者之一.2015年到20 ...

  6. python:实现skew heap倾斜堆算法(附完整源码)

    python:实现skew heap倾斜堆算法 from __future__ import annotationsfrom collections.abc import Iterable, Iter ...

  7. “扬帆起航 开启DHR新纪元” 中建信息携手SAP SuccessFactors 人力资源“进化”之旅...

    申耀的科技观察 读懂科技,赢取未来! 7月19日,中建信息携手SAP,在天府之国成都引领合作伙伴开启了一场SAP SuccessFactors 人力资源'进化'之旅".SAP Success ...

  8. java 堆和栈 数据结构_数据结构的栈和堆和程序中的堆和栈

    在计算机领域,堆栈是一个不容忽视的概念,我们编写的C语言程序基本上都要用到.但对于很多的初学着来说,堆栈是一个很模糊的概念.堆栈:一种数据结构.一个在程序运行时用于存放的地方,这可能是很多初学者的认识 ...

  9. java 浅堆 深堆_JVM中的一个小知识点:深堆和浅堆的概念

    java中的堆内存算是整个内存区域中最重要的一块,几乎所有的对象都分配在堆内存.在堆内存中有两个主要的概念需要我们理解,这对分析java堆内存的故障有着重要的作用,分别是深堆和浅堆. 一.概念 我们先 ...

  10. python树结构实现小顶堆_数据结构和算法入门之小顶堆和大顶堆Python实现

    首先简单提一下小顶堆和大顶堆,其本质是一颗完全二叉树,不同点在于:除叶子节点外,小顶堆的每个父节点的key都要比其左右两个子节点的key小:大顶堆的每个父节点的key都要比其左右两个子节点的key大. ...

最新文章

  1. jquery中的attr()和prop()
  2. 插入数据,已存在则不插入
  3. 利用Vagrant and VirtualBox搭建core os环境
  4. 什么是事件冒泡?如何用jquery/js阻止事件冒泡?阻止冒泡有什么作用?小生来抛个砖。...
  5. 自由、开源及其敌人 —— RMS事件簿
  6. CentOS系统安装Java
  7. struts2.3+spring3.2+hibernate4.2例子
  8. 55. Attribute name 属性
  9. windows电脑借助多开软件实现ZALO程序多开
  10. 锐起无盘找不到服务器,锐起无盘出现重启后连接不到服务器
  11. 天猫八大策略人群京东十大靶向人群简介
  12. C语言 java 判断闰年,一个月有多少天
  13. R可视化会出现的问题1
  14. java语言简介论文,基于Java的Web论坛开发.doc
  15. pdfminer __init__() got an unexpected keyword argument ‘codec‘解决方案
  16. 中国空气质量AQI热力图
  17. 【学术信息】2019年期刊中科院分区-环境科学与生态学
  18. ios 输入法扩展_iOS 11自带输入法新增3个小功能,贴心!
  19. windows7 系统搭建webdav服务
  20. Redis项目应用场景与实例(三):队列(List)

热门文章

  1. Range Coder编码比特流
  2. java的fprintf_fprintf不接受一个字符数组吗?
  3. idea 关闭检查更新_intellij idea怎么关闭自动更新
  4. roc曲线spss怎么做_统计第十三课:SPSS ROC曲线
  5. 创建室内导航地图的9个步骤
  6. 《java语言程序设计》泽勒一致性问题
  7. 心理学与生活《感知与记忆》
  8. C++内存分配(operator new)
  9. python打包时出现RecursionError: maximum recursion depth exceeded的解决方法
  10. 二进制转化成ascll_怎样将二进制转ascii码