当前位置:   article > 正文

算法设计搬运(3)——Heaps_8-2 the 2-3-4 heaps

8-2 the 2-3-4 heaps

前言

570 Lecture 3 的内容。 Lecture 3 的前半段相当于 review,所讲 binary heap 内容基本被都数据结构覆盖,基础的可能会简略一点。后半段讨论了 Binomial Heap 和 Fibonacci Heap。

3. Heaps

3.1 Binary Heap

二叉堆(最小堆):complete binary tree that satisfies the heap odering.
也就是首先它是个完全二叉树,其次满足堆的性质,(没有声明默认最小)即左右子树都小于等于根元素。堆顶元素最小,或者理解为优先级最高。
实现是用 array,array[1…n],对于 i-th 元素,左孩子2i,右孩子2i+1,一般提供几种操作 insert,deleteMin,heapify和changeKey。

  • Insert. 插入元素放在 array 里 n+1 的位置,依次与 parent比较,如果小就交换,直到根节点。因为是完全二叉树,所以 worst-case 比较次数O(log n),swap O(1),因此复杂度 O(log n)。
    insert

  • DeleteMin. 把堆顶元素和最后一个元素交换,堆(array)的长度 -1,从新的根节点开始,如果其比左右孩子中任意一个小,那么就与左右孩子中更小的交换,直至不需要交换。worst case 也是从根节点一直交换到叶子节点,O(log n)。
    deleteMin

  • Heapify. 一般用来 offline 建堆。从前array的 n/2 处开始从底向上,对于每一个元素判断是否需要与左右孩子交换。不同于通过 insertion 建堆,Heapify O(n).

例:对 4,7,3,6,8,5,2,1 建堆,n insertion O(nlogn):
Build Heap

而 Heapify,从 n/ 2 处开始所有元素都只可能往叶子节点交换。根节点最坏情况交换 h 次,其2个子节点最多交换 h-1 次 … 2h-1 在倒数第二层,交换一次。对于 worst case,total swap = 1 ⋅ h + 2 ⋅ ( h − 1 ) + . . . + 2 h − 1 ⋅ 1 = ∑ i = 1 h 2 h − i ⋅ i = O ( 2 h ) 1·h +2·(h-1)+...+2^{h-1}·1 = \sum_{i=1}^{h}2^{h-i}·i = O(2^h) 1h+2(h1)+...+2h11=i=1h2hii=O(2h),因为 h = ⌊ log ⁡ n ⌋ h = \lfloor \log n\rfloor h=logn,heapify 整体复杂度 O ( n ) O(n) O(n).
Heapify

  • changeKey. 一般是优先队列的 op,修改一个节点的key。实现:如果 key 变小,那么就往上去比较交换,直到 root。如果变大,那么往叶子方向跟孩子比较交换(更小者),O(logn)。

Discussion Problem 1. 对于存储元素1,2,…,15 的堆最小的叶子节点可能是______。

Solution. 4. 如图。example
还有一些其他数据结构的内容比如堆排序、top K 问题,以及归并 k 个有序数组。

解决 top K 有两种思路(给定unsorted array)。一种是直接建一个长度为 n 的最大堆,然后 deleteMax k 次。O(n) 建堆,deleteMax k 次 O(klogn),整体 O(n+klogn).
另一种思路则维护一个长度为 k 的堆,deleteMin 和 insert n-k 次,这样O(k) 建堆,维护需要 O(nlogk),整体复杂度O(nlogk).

这里的 top K 问题可能会涉及到 offline 和 online 的场景,也就是说我们能不能一次性获取到所有数据——是给定array,还是要一个一个数的等。思路二的好处是可以应对 online 场景,O(klogk) 建堆,n-k次 deletesMin 和 insert O(nlogk),整体 O(nlogk)。而如果要用思路一必须得一个一个 insert 的s建堆,那么整体复杂度 O(nlogn) 就很不理想了。而 offline 二者就其实差不多,所以算法很多时候还是得结合场景。

3.2 Binomial Heaps

回想上一篇的 amortized tree,二者相似。这里二项堆也是为了得到更好的 amortized cost。
首先是二项树,B0 是一个单一节点,Bn 是由两个 Bn-1合并而来。如图。
Binomial Tree

而 Binomial Heaps 就是 一个结构同 Binomial Tree 的链表,每一个树的秩都是唯一的,且每一棵树都具备堆的性质。每一个节点都包含了它的数值和它的秩,parent,child 和 sibling.

Binomial Heaps
那么就像 Binary counter一样,二项堆可以容纳任意个数,存放 n 个数的二项堆最多有 logn 个 堆。插入操作相当于是一次 increment。每一次插入,都是再链表里加入 B0,因此可能需要进行合并。最差情况下是所有的 bits 都要 flip,O(logn) 次合并(merge 先比较大小,然后指针 cost O(1) ),所以 worst-case 插入O(logn)。而对于 n 次插入而言,Binary Counter n 次 incremet,cost to flip each bit 都是 1,所以 amortized cost per operation = O(1). 如果用 accounting method 来分析的话那就是 O(2),1个 insert消耗掉,另一个用来给后续可能的 merge存着。
:insert 4, 7, 3, 2, 8, 3, 5, 6, 9 to an empty (eager) binomial heap.

insert (1)

insert (2)

而 deleteMin 首先要 findMin, O(logn) 因为 logn 个堆。而后需要删一个根元素就必然会 split 一个堆,worst-case 同样是所有 bits 都要 flip,100$\implies$011。所以 O(logn)。Delete的复杂度取决于最小值所在的位置,假设它是 Bi+1的 root,那么这次deleteMin 可能会有 i 次合并——i 个 filpped bits。尽管我们不能确定每一次最小元素所在位置——每一次的复杂度,但是对于 n 次 deleteMin,对应 B0 merge n-1次,B1 merge n-2次,B2 merge n-4次… total work = O(nlogn). Amortized cost per operation 仍然是 O(logn),并没有比binary heap 有提升。

deleteMin

在这里做一个 Binomial 和 Binary heap 建堆的比较。

Binary heap 建堆 分为 online 和 offline。worst-case 前者 n 次 insert, Θ \Theta Θ(nlogn);后者 heapify Θ \Theta Θ(n)。而 Binomial heap 建堆的amortized 复杂度 Θ \Theta Θ(n)

(这是对于 eager binomial heap的情况,也就是每一次插入都要去维护数据结构)

与之对应的是 lazy binomial heap,插入的时候我们就只是把节点放在双向链表里,其他什么都不管,O(1)。维护的事情全部交给 deleteMin 来做。提升 insert性能 ,O(logn)    ⟹    \implies O(1)(worst-case),同时保持 deleteMin O(logn) 的 amortized cost。

lazy binomial heap 在插入时不再保持每一个 heap order 的 rank 唯一的性质。在 deleteMin 时,做两件事 一个是在森林里找到最小根,split 那个binomial heap,二是合并所有 oder 不唯一的,直到形成标准的 binomial heaps,order 唯一。这样来看最差情况其实是 O(n)。毕竟我们无法使 insert 和 deleteMin 都有 常数的 amortized cost,回想 Lecture 1 介绍的定理,“no comparison-based…”

3.3 Fibonacci Heaps

Lazy Binomial heaps 的扩展。对于 heaps collection的维护还是只交给 deleteMin,Fibonacci heaps 支持复杂度更低的 decreaseKey. 前面 lazy insert已经不再保持 binomial heap order 的唯一性,Fibonacci heaps 在此基础上不再要求链表里的节点都是标准的 binomial heap。

decreaseKey 不需要再维护 二项堆的结构,我们就直接把需要 decreasekey 的 node 直接 cut 掉,然后再加入到 collection 里面。这样就有了 O(1) 的复杂度。deleteMin的维护则要变得更复杂,这里还有很多问题但是 Victor 压根没讲。在理想情况下,amortized 复杂度O(logn)。

小节

这部分后面的内容 Victor 课上几乎都没讲明白,甚至连 为什么要引入 Binomial Heap和 Fibonacci Heap 的 motivation 都没讲。Lazy Binomial Heap 中 deleteMin 的实现和 amortized analysis,以及 Fibonacci Heap 的 实现和相应问题, decreaseKey 造成 森林里面 每一个 heap 的 shape 不再 well-constrained,对于 n 个 nodes,我们最多跟能会有 n 1 2 n^{\frac{1}{2}} n21 个 tree,相比之前 最多 logn 个 heap,最后再去维护就不能再保证deleteMin O(logn) 的 amortized 复杂度。

结果就是这部分内容,就这样不了了之了,考试的时候也没有考。Victor 天天吹自己编的教材,“我编的教材里所有内容浓缩了所有面试时可能会遇到的问题,认真看了,包你们找到工作…” 这部分课上没讲,算法设计上其实也没有… 但我还是会单独拿出来补充吧。毕竟 stanford cs 166 花了 两个 lecture,500 页的 slides 讲了这两个数据结构…

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/707512
推荐阅读
相关标签
  

闽ICP备14008679号