二项式堆:证明合并在O(log n)时间内运行

时间:2015-09-05 16:46:17

标签: algorithm data-structures functional-programming big-o ml

我正在阅读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)次,但由于insTreeO(log n)最糟糕的情况,您能解释一下mergeO(log n) 1}}?

1 个答案:

答案 0 :(得分:4)

首先请注意,merge最多会被调用(numNodes ts1 + numNodes ts2)次,这是O(log n)次。 (为了清楚起见,ts1ts2是二叉树的列表,其中等级r的树恰好包含2^r个节点,每个等级最多可以出现因此,O(log n1)中的ts1O(log n2) ts2中有n1个这样的树,其中n2n=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)次调用,每次调用都是固定时间(因为我们会分别调用insTreelink是常量时间)

=&GT;整个合并操作为O(log n)

编辑:顺便说一下,合并二项式堆非常类似于添加二进制数。当且仅当二进制数n具有&#39; 1&#39;时,大小为r的堆将具有等级n的树。在2^r位置。合并这些堆时,从最低等级到最高等级 - 或最不重要到最重要的等级。需要链接相同等级的树(添加了#39;并且插入&#34;携带&#34;进入更高级别的职位。