Lazy Binomial Heaps
Lazy Binomial Heaps
- motivation
- Meldable Priority Queue
- 更多细节——Recap from last time
- lazy binomial heap
- where we stand
- coalesce step
- The story so far
- 后记
motivation
为什么我们需要Binomial heaps(二项堆)? Binary heaps(二叉堆) 实现的优先队列就已经有了 O(logn) 复杂度的 enqueue(insert) 和 extractMin(deleteMin),findMin O(1), 实际运作过程中就已经很快了,为何还需要其他 堆 呢?
因为很多图算法都不止依赖于优先队列的这两种操作,还依赖于它提供的额外操作: meld (merge or union)——合并两个优先队列 (MSTs via Cheriton-Tarjan) ,decreaseKey——提高队列内某个元素的priority (Shortest paths via Dijkstra),add_to_all——add $\Delta $k to the keys of each element in pq.
Meldable Priority Queue
试想如何用二叉堆实现的优先队列实现两个 pq 的合并呢?可以两个混在一块 heapify,O(n) 看起来还可以;或是调用接口 A.insert(B.deleteMin()),O(nlogn) 看起来就不太行。
因为二叉堆是完全二叉树,所以很难简单地把两个二叉堆通过 link 合并成新的二叉堆。
而如果我们用二进制来表示这两个 pq,那么合并相当于 二进制加法,这样复杂度就变成了 O(logn+logm)。在这种思路下,我们把 n 和 m 表示成两个 packets collection每一个 packet 2 的幂次大小,用来存数。然后用指针把这些 packet 和 node link,这样合并就变成了:
更多细节——Recap from last time
我们在算法设计搬运(3)——Heaps这部分内容里讲了 binomial tree 和 binomial heaps 的操作及性能分析。因为我们在这里已经不是在搬运 570 的内容了,而是在补充 Victor 在 570 上略过的知识,为它们做详细补充,更详细的的披露细节,首先来是 binomial tree 的性质。
Properties of Bk
- 含有 2k 个 nodes
- height 为 k
- 第iii层有(ik)(_i^k)(ik)个 nodes
- rank(root(Bk)) = rank(Bk) = k
- 根的孩子从左到右为 Bk-1, Bk-2,…, B0.
而 binomial heap H 则是 binomial tree 的 set,且 set 中的 B 满足 min-heap 的性质。对于 eager binomial heap,我们还要求 B 的 rank 唯一。
然后之前没有涉及到 meld 操作,那么对于 eager binomial heap,meld(H1,H2): H2 order 低到高往 H1 里添加,扫描对应位置,rank 不唯一则比较根大小,link,order+1,直至 rank 唯一,直到全部添加完,O(log n)。另外,insert(H,v) 的实现实际上就是 MAKE-HEAP(v), 在对这个只含单一节点的 heap 和 H 进行 meld。
其他操作和复杂度分析详见算法设计搬运(3)——Heaps 和 Potential Method —— amortized analysis。
lazy binomial heap
where we stand
在继续下面的内容之前我们先看一下 eager binomial heap 的性能表现。
(MINIMUM 因为存了指针,在 insert 和 extractMin 时顺便 update,所以Θ(1)\Theta(1)Θ(1).)
根据“对于 comparison-based sort 需要 Ω(nlogn)\Omega(n\log n)Ω(nlogn)”这个定理,看看我们现在的处境可以发现,能优化的地方不多。我们不可能让 insert 和 extractMin 都优化到更快——指都小于O(logn),但是却可以考虑使其中一项操作变得更快。
那么就考虑优化 insert 吧!看看能不能使在 worst-case 也可以 O(1)O(1)O(1),毕竟删前总要插。那么因为 insert 或 enqueue 是用 meld 实现的,那么 meld 也必须 O(1)O(1)O(1)了。
问题:为什么我们在插入时就要维护呢,我们都不一定要对新插入进来的节点做任何操作?
思路:我们索性 insert 或 meld 的时候就只维护 min 指针,然后直接把 H2 直接连进来,复杂度O(1)O(1)O(1),然后如果有其他要维护的事情就全交给 extractMin 吧!
例: 对于 lazy binomial heap 插入 4, 7, 3, 6, 5. (In practice,实现是双向循环链表)
试想一下这样实现 lazy meld 之后,extractMin 会怎样?
- 先 remove min 指针所指向 binomial tree 的 root,把 Bk 分裂成 BK-1…B0 再 lazy meld 回来
- 再 update min 指针
可达鸭眉头一皱,发现在最后 update 时的复杂度取决于 此时 heap 里面 tree 的个数,O(t)。而t = O(n),于是 extractMin O(n)。
像极了中学假期在家的你。白天父母外出工作,于是玩的时候不需要考虑收拾可以随意地造。其余的事情就等着之后掐着父母下班的点再把一切收拾干净,装作这一天平静度过什么都没有发生一样。恭喜你年纪轻轻就已经是个优化带师,成功地把 van 的复杂度降到了最低。
接着来解决 extractMin 变 O(n) 的问题。分析可知这是由于我们不再限制 Bk 的order唯一,meld 时只单纯 link。那么就考虑我们对应 lazy meld,在 extractMin 时把该合并的合并了,保证 order 唯一这样我们的树的个数就变 O(log n)。
这个在 extractMin 时重新合并 tree 使 order 再次唯一的操作在某些教材上称之为 coalesce step.
coalesce step
简言之, coalesce step 就是在extractMin之后,update min 指针之前合并所有order相同的 tree 使 order 唯一。
考虑到同 order 合并,且 order 破碎,使用基排序来高效合并。
先创建 O(logn)个箱子,O(logn)。再 distribute 按 order 所有的 tree,O(t)。再合并所有需要合并的 tree,O(t)。总复杂度 O(t+logn)。
所以此时 extractMin 的实现:
- 先 remove min 指针所指向 binomial tree 的 root,把 Bk 分裂成 BK-1…B0 再 lazy meld 回来, O(logn)
- 再 coalesce step, O(t+logn)
- 最后 update min 指针, O(logn)
很遗憾,extractMin worst-case 复杂度 O(t+logn) = O(n)。heap 里全是 B0. 而 insert, meld, minimum O(1). 即便我们此时还不考虑 decreaseKey,但依旧是O(logn),取决于树的高度。
The story so far
lazy binomial heap 的 worst-case 性能似乎看起来并不乐观。实际上我们是以牺牲了extractMin 的性能为代价换取了 meld 的高效。那么这个数据结构的均摊复杂度如何呢?
继续使用上次扩充的 potential method.
首先 meld 和 insert worst-case Θ(1)\Theta(1)Θ(1), amortized 同样 Θ(1)\Theta(1)Θ(1)。
Minimum 存了指针,所以依旧Θ(1)\Theta(1)Θ(1)。
最后是关于extractMin的 amortized analysis. 依旧令Φ(S)\Phi(S)Φ(S)表示当前 heap 里 tree 的数量。假设 extractMin 前 Φ(Sbefore)=t\Phi(S_{before}) = tΦ(Sbefore)=t。
actual cost of step 1 =O(logn)= O(\log n)=O(logn)
actual cost of step 2 =O(t+logn)= O(t+\log n)=O(t+logn)
actual cost of step 3 =O(logn)= O(\log n)=O(logn)(前面都提到过)
Φ(Safter)=logn\Phi(S_{after}) = \log nΦ(Safter)=logn
ΔΦ=−t+logn\Delta\Phi = -t + \log nΔΦ=−t+logn, actual cost =O(t+logn)= O(t+\log n)=O(t+logn).
因此“均摊”复杂度 = O(t+logn)+C⋅(−t+logn)=O(logn)O(t+\log n) + C\cdot (-t+\log n) = O(\log n)O(t+logn)+C⋅(−t+logn)=O(logn)
最终 lazy binomial heap 的性能如下:
(两个性能的图均来自 Stony Brook CSE-548 lecture9)
后记
主要参考了大S的 cs-166,Stony Brook的 CSE-548。
前者会讲很多思路,好像旨在告诉你提出解决办法的人是他们如何思考这个问题的,把你带入到情境中。但是有时候会显得很冗长,啰嗦。而实际上虽然内容很长,200+的slides,但其实并没有披露特别多的细节。而且因为屏蔽了一些细节,所以在一些时候分析的时候就会跟屏蔽细节的结论相悖。
后者很扎实、很干。上来就硬货怼脸的感觉,而且会涉及到比较多的细节,很详尽。可能因为是CSE的缘故…总之如果抱着致知的态度,刨根问底一探究竟的话,极为推荐。可能大S的人都是那种知道顶层思路,享受自己回去自己研究实现的乐趣。确实本来就没有一个正确答案,只要思路对,能实现,细节自己慢慢扣是极好的。
啊…如果本着膜一下名校,去看下CMU的课件,我觉得还是算了吧。看了也白看,内容很少,看了也白看,而且写到 3. Binomial heaps 后面就跟了一句话,To be finished. 在后面就是下一个 lecture的另外的内容了…
最后记一下这些 slides 中的小错。cs-166: performance score find_min Θ(1)\Theta(1)Θ(1),而在分析时采用的是不维护 min 指针而是去find_min O(t),感觉没得洗。另外就是太长了…不利于阅读…CSE-548 对于lazy binomial heap 是否维护 min 指针的描述前后矛盾。维护顺带的事儿,不维护的话,O(t)啊!?另外可能会不一致在一些操作的先后顺序是先合并还是先remove没有影响。
Lazy Binomial Heaps相关推荐
- 并行计算--并发构造纵览
并行计算--并发构造纵览 2010年10月22日 作者简介: 孙奇辉,现任某电信公司软件工程师.对面向对象分析和设计,函数式编程,并行计算等有浓厚兴趣. E-mail:qihui.sun@gmail. ...
- 单例模式的两种实现方式对比:DCL (double check idiom)双重检查 和 lazy initialization holder class(静态内部类)...
首先这两种方式都是延迟初始化机制,就是当要用到的时候再去初始化. 但是Effective Java书中说过:除非绝对必要,否则就不要这么做. 1. DCL (double checked lockin ...
- uscao 线段树成段更新操作及Lazy思想(POJ3468解题报告)
线段树成段更新操作及Lazy思想(POJ3468解题报告) 标签: treequerybuildn2cstruct 2011-11-03 20:37 5756人阅读 评论(0) 收藏 举报 分类: ...
- HYSBZ - 1798 Seq 维护序列seq 线段树lazy标记
传送门 这道题属实是线段树的道比刷题,又加又乘的,当然还可能会有乘除,阶乘等等可能的情况. 对于这道题,主要的一个就是怎么记录lazy标记,首先的话一个数组是肯定不行的,设乘的为lazy,加的为add ...
- hibernate 全面学习【lazy策略 】
2019独角兽企业重金招聘Python工程师标准>>> lazy策略可以用在: * <class>标签上:可以取值true/false * <property> ...
- scala学习笔记-过程、lazy值和异常(6)
过程 在Scala中,定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Unit.这样的函数就被称之为过程.过程通常用于不需要返回值的函数. 过程还有一种写法,就是 ...
- 怎么确定迭代器后面还有至少两个值_JS Lazy evaluation:可迭代对象与迭代器
本文已经过原作者 MelkorNemesis 授权翻译. Lazy evaluation Lazy evaluation常被译为"延迟计算"或"惰性计算",指的 ...
- R语言负二项分布函数Negative Binomial Distribution(dnbinom, pnbinom, qnbinom rnbinom )实战
R语言负二项分布函数Negative Binomial Distribution(dnbinom, pnbinom, qnbinom & rnbinom )实战 目录 R语言负二项分布函数Ne ...
- R语言卡方分布函数Binomial Distribution(dchisq, pchisq, qchisq rchisq)实战
R语言卡方分布函数Binomial Distribution(dchisq, pchisq, qchisq & rchisq)实战 目录 R语言卡方分布函数Binomial Distribut ...
- R语言二项分布函数Binomial Distribution(dbinom, pbinom, qbinom rbinom)实战
R语言二项分布函数Binomial Distribution(dbinom, pbinom, qbinom & rbinom)实战 目录 R语言二项分布函数Binomial Distribut ...
最新文章
- java nanos_java命名空间java.util.concurrent.locks接口condition的类成员方法:
awaitnanos定义及介绍...
- python只能对列表进行切片_Python3:类型错误:列表索引必须是整数或切片,而不是s...
- 十五、中文词向量训练二
- [HNOI2019]校园旅行
- 数据调度组件:基于Azkaban协调时序任务执行
- map函数的用法python,详解Python map函数及Python map()函数的用法
- Under the Hoods of Cache Fusion, GES, GRD and GCS
- python是什么类型的语言-Python是什么?简单了解pythonp-入门
- androidstudio调用系统相机为什么resultcode一直返回0_机器视觉系统原理及学习策略...
- 2018清华计算机专业优秀学生名单,2018信息学竞赛清华北大优秀学生签约名单
- H5动画实现简单的转盘抽奖。
- 用户兴趣模型分类以及推荐系统技术调研
- 简单几步去掉百度热搜
- 联通短信息中心号码,联通服务中心号码速查
- java宠物小精灵_4978:宠物小精灵之收服
- dva是什么游戏_守望先锋DVA全互动台词一览
- 用stocker进行股票预测
- 基于jsp+java+ssm的农产品购物商城系统-计算机毕业设计
- 2018年爬虫代理IP提供商对比
- 深入理解卷积神经网络(附代码,底层实现)
热门文章
- Thread-Specific Data(线程私有数据)
- 用计算机专业术语写寄语,教师给计算机专业学生寄语
- iOS App上架遇到的错误(ERRORITMS-90096: )
- Word 文档乱码-请选择使文档可读的编码 重启电脑-不是解决方法的解决方法(可能已经晚了)
- Python 圆拟合
- 摩尔庄园服务器显示不出,摩尔庄园电脑为什么玩不了 摩尔庄园电脑玩不了解决方案...
- W806串口管脚复用
- ma5671怎么设置_电信/联通/移动,更换华为MA5671光猫详细教程
- [机器学习入门] 李宏毅机器学习笔记-21(Transfer Learning part 1 ; 迁移学习 part 1)
- js 仿微信投诉—引入vue.js,拆分组件为单个js