赞
踩
570 Lecture 3 的内容。 Lecture 3 的前半段相当于 review,所讲 binary heap 内容基本被都数据结构覆盖,基础的可能会简略一点。后半段讨论了 Binomial Heap 和 Fibonacci 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)。
DeleteMin. 把堆顶元素和最后一个元素交换,堆(array)的长度 -1,从新的根节点开始,如果其比左右孩子中任意一个小,那么就与左右孩子中更小的交换,直至不需要交换。worst case 也是从根节点一直交换到叶子节点,O(log n)。
Heapify. 一般用来 offline 建堆。从前array的 n/2 处开始从底向上,对于每一个元素判断是否需要与左右孩子交换。不同于通过 insertion 建堆,Heapify O(n).
例:对 4,7,3,6,8,5,2,1 建堆,n insertion O(nlogn):
而 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)
1⋅h+2⋅(h−1)+...+2h−1⋅1=∑i=1h2h−i⋅i=O(2h),因为
h
=
⌊
log
n
⌋
h = \lfloor \log n\rfloor
h=⌊logn⌋,heapify 整体复杂度
O
(
n
)
O(n)
O(n).
Discussion Problem 1. 对于存储元素1,2,…,15 的堆最小的叶子节点可能是______。
Solution. 4. 如图。
还有一些其他数据结构的内容比如堆排序、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 二者就其实差不多,所以算法很多时候还是得结合场景。
回想上一篇的 amortized tree,二者相似。这里二项堆也是为了得到更好的 amortized cost。
首先是二项树,B0 是一个单一节点,Bn 是由两个 Bn-1合并而来。如图。
而 Binomial Heaps 就是 一个结构同 Binomial Tree 的链表,每一个树的秩都是唯一的,且每一棵树都具备堆的性质。每一个节点都包含了它的数值和它的秩,parent,child 和 sibling.
那么就像 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.
而 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 有提升。
在这里做一个 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…”
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 讲了这两个数据结构…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。