我正在阅读Okasaki's Purely Functional Data Structures并正在尝试进行一些练习。其中一个是证明二项式堆merge
需要O(log n)
时间,其中n
是堆中节点的数量。
functor BinomialHeap (Element:ORDERED):HEAP=
struct
structure Elem=Element
datatype Tree = Node of int*Elem.T*Tree list
type Heap = Tree list
fun link (t1 as Node (r,x1,c1), t2 as Node (_,x2,c2))=
if Elem.leq(x1,x2)
then Node (r+1,x1,t2::c1)
else Node (r+1,x2,t1::c2)
fun insTree (t,[])=[t]
|insTree (t,ts as t'::ts')=
if rank t < rank t' then t::ts else insTree(link(t,t'),ts')
fun insert (x,ts)=insTree(Node(0,x,[]),ts) (*just for reference*)
fun merge (ts1,[])=ts1
|merge ([],ts2)=ts2
|merge (ts1 as t1::ts1', ts2 as t2:ts2')=
if rank t1 < rank t2 then t1::merge(ts1',ts2)
else if rank t2 < rank t1 then t2::merge(ts1,ts2')
else insTree (link(t1,t2), merge (ts1',ts2'))
end
很明显,merge
会将自己称为max(numNodes ts1, numNodes ts2)
次,但由于insTree
是O(log n)
最糟糕的情况,您能解释一下merge
是O(log n)
1}}?
答案 0 :(得分:4)
首先请注意,merge
最多会被调用(numNodes ts1 + numNodes ts2)
次,这是O(log n)
次。 (为了清楚起见,ts1
和ts2
是二叉树的列表,其中等级r
的树恰好包含2^r
个节点,每个等级最多可以出现因此,O(log n1)
中的ts1
和O(log n2)
ts2
中有n1
个这样的树,其中n2
和n=n1+n2
是堆和insTree
。)
要注意的关键点是merge
每个等级最多调用一次(通过log_2(n)
或递归),最大可能等级为insTree
。原因如下:
如果从merge
调用r = rank t1 = rank t2
,则说link(t1,t2)
,r+1
将具有等级insTree
。因此,我们要求r+1
为排名merge(ts1', ts2')
。现在想想ts1'
会发生什么。让ts2'
和 r' >= r+1
中作为树发生的最小排名为insTree
。然后merge
将再次从r'+1
调用r'
,因为等级r'+1
的两棵树将被链接以形成等级merge(ts1', ts2')
的树。但是,合并的堆r'
因此不包含排名为insTree
的树,因此之前对r'
的调用不能超过{{1} }}
所以把事情放在一起:
insTree
最多被调用O(log n)
次,每次调用都是常量时间(因为我们将递归计为单独的调用)
merge
最多被O(log n)
次调用,每次调用都是固定时间(因为我们会分别调用insTree
,link
是常量时间)
=&GT;整个合并操作为O(log n)
。
n
具有&#39; 1&#39;时,大小为r
的堆将具有等级n
的树。在2^r
位置。合并这些堆时,从最低等级到最高等级 - 或最不重要到最重要的等级。需要链接相同等级的树(添加了#39;并且插入&#34;携带&#34;进入更高级别的职位。