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 treebinomial 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 需要 Ω(nlog⁡n)\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.

首先 meldinsert 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(log⁡n)= O(\log n)=O(logn)
actual cost of step 2 =O(t+log⁡n)= O(t+\log n)=O(t+logn)
actual cost of step 3 =O(log⁡n)= O(\log n)=O(logn)(前面都提到过)
Φ(Safter)=log⁡n\Phi(S_{after}) = \log nΦ(Safter​)=logn

ΔΦ=−t+log⁡n\Delta\Phi = -t + \log nΔΦ=−t+logn, actual cost =O(t+log⁡n)= O(t+\log n)=O(t+logn).
因此“均摊”复杂度 = O(t+log⁡n)+C⋅(−t+log⁡n)=O(log⁡n)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相关推荐

  1. 并行计算--并发构造纵览

    并行计算--并发构造纵览 2010年10月22日 作者简介: 孙奇辉,现任某电信公司软件工程师.对面向对象分析和设计,函数式编程,并行计算等有浓厚兴趣. E-mail:qihui.sun@gmail. ...

  2. 单例模式的两种实现方式对比:DCL (double check idiom)双重检查 和 lazy initialization holder class(静态内部类)...

    首先这两种方式都是延迟初始化机制,就是当要用到的时候再去初始化. 但是Effective Java书中说过:除非绝对必要,否则就不要这么做. 1. DCL (double checked lockin ...

  3. uscao 线段树成段更新操作及Lazy思想(POJ3468解题报告)

    线段树成段更新操作及Lazy思想(POJ3468解题报告) 标签: treequerybuildn2cstruct 2011-11-03 20:37 5756人阅读 评论(0) 收藏 举报  分类: ...

  4. HYSBZ - 1798 Seq 维护序列seq 线段树lazy标记

    传送门 这道题属实是线段树的道比刷题,又加又乘的,当然还可能会有乘除,阶乘等等可能的情况. 对于这道题,主要的一个就是怎么记录lazy标记,首先的话一个数组是肯定不行的,设乘的为lazy,加的为add ...

  5. hibernate 全面学习【lazy策略 】

    2019独角兽企业重金招聘Python工程师标准>>> lazy策略可以用在: * <class>标签上:可以取值true/false * <property> ...

  6. scala学习笔记-过程、lazy值和异常(6)

    过程 在Scala中,定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Unit.这样的函数就被称之为过程.过程通常用于不需要返回值的函数. 过程还有一种写法,就是 ...

  7. 怎么确定迭代器后面还有至少两个值_JS Lazy evaluation:可迭代对象与迭代器

    本文已经过原作者 MelkorNemesis 授权翻译. Lazy evaluation Lazy evaluation常被译为"延迟计算"或"惰性计算",指的 ...

  8. R语言负二项分布函数Negative Binomial Distribution(dnbinom, pnbinom, qnbinom rnbinom )实战

    R语言负二项分布函数Negative Binomial Distribution(dnbinom, pnbinom, qnbinom & rnbinom )实战 目录 R语言负二项分布函数Ne ...

  9. R语言卡方分布函数Binomial Distribution(dchisq, pchisq, qchisq rchisq)实战

    R语言卡方分布函数Binomial Distribution(dchisq, pchisq, qchisq & rchisq)实战 目录 R语言卡方分布函数Binomial Distribut ...

  10. R语言二项分布函数Binomial Distribution(dbinom, pbinom, qbinom rbinom)实战

    R语言二项分布函数Binomial Distribution(dbinom, pbinom, qbinom & rbinom)实战 目录 R语言二项分布函数Binomial Distribut ...

最新文章

  1. java nanos_java命名空间java.util.concurrent.locks接口condition的类成员方法: awaitnanos定义及介绍...
  2. python只能对列表进行切片_Python3:类型错误:列表索引必须是整数或切片,而不是s...
  3. 十五、中文词向量训练二
  4. [HNOI2019]校园旅行
  5. 数据调度组件:基于Azkaban协调时序任务执行
  6. map函数的用法python,详解Python map函数及Python map()函数的用法
  7. Under the Hoods of Cache Fusion, GES, GRD and GCS
  8. python是什么类型的语言-Python是什么?简单了解pythonp-入门
  9. androidstudio调用系统相机为什么resultcode一直返回0_机器视觉系统原理及学习策略...
  10. 2018清华计算机专业优秀学生名单,2018信息学竞赛清华北大优秀学生签约名单
  11. H5动画实现简单的转盘抽奖。
  12. 用户兴趣模型分类以及推荐系统技术调研
  13. 简单几步去掉百度热搜
  14. 联通短信息中心号码,联通服务中心号码速查
  15. java宠物小精灵_4978:宠物小精灵之收服
  16. dva是什么游戏_守望先锋DVA全互动台词一览
  17. 用stocker进行股票预测
  18. 基于jsp+java+ssm的农产品购物商城系统-计算机毕业设计
  19. 2018年爬虫代理IP提供商对比
  20. 深入理解卷积神经网络(附代码,底层实现)

热门文章

  1. Thread-Specific Data(线程私有数据)
  2. 用计算机专业术语写寄语,教师给计算机专业学生寄语
  3. iOS App上架遇到的错误(ERRORITMS-90096: )
  4. Word 文档乱码-请选择使文档可读的编码 重启电脑-不是解决方法的解决方法(可能已经晚了)
  5. Python 圆拟合
  6. 摩尔庄园服务器显示不出,摩尔庄园电脑为什么玩不了 摩尔庄园电脑玩不了解决方案...
  7. W806串口管脚复用
  8. ma5671怎么设置_电信/联通/移动,更换华为MA5671光猫详细教程
  9. [机器学习入门] 李宏毅机器学习笔记-21(Transfer Learning part 1 ; 迁移学习 part 1)
  10. js 仿微信投诉—引入vue.js,拆分组件为单个js