Okasaki 在Purely Functional Data Structures(第 22 页)中的实现分为两部分:一是合并森林,一是传播进位。这让我觉得比一次性版本更难分析,也可能更慢。我错过了什么吗?
冈崎的实现:
函子 BinomialHeap (元素:ORDERED):HEAP= 结构 结构元素=元素 数据类型 Tree = int*Elem.T*Tree 列表的节点 类型堆 = 树列表 有趣的链接(t1 作为节点(r,x1,c1),t2 作为节点(_,x2,c2))= 如果 Elem.leq(x1,x2) 然后节点 (r+1,x1,t2::c1) 否则节点 (r+1,x2,t1::c2) 有趣的 insTree (t,[])=[t] |insTree (t,ts as t'::ts')= 如果排名 t < 排名 t' 则 t::ts 否则 insTree(link(t,t'),ts') fun insert (x,ts)=insTree(Node(0,x,[]),ts) (*仅供参考*) 有趣的合并 (ts1,[])=ts1 |合并 ([],ts2)=ts2 |合并(ts1 作为 t1::ts1',ts2 作为 t2:ts2')= 如果排名 t1 < 排名 t2 则 t1::merge(ts1',ts2) 否则,如果排名 t2 < 排名 t1 则 t2::merge(ts1,ts2') 否则 insTree(链接(t1,t2),合并(ts1',ts2')) 结尾
这让我觉得很难分析,因为你必须证明传播所有进位的成本的上限(见下文)。我想出的自上而下的合并实现更明显是 O(log n) 其中 n 是较大堆的大小:
函子 BinomialHeap (元素:ORDERED):HEAP= 结构 结构元素=元素 数据类型 Tree = int*Elem.T*Tree 列表的节点 类型堆 = 树列表 有趣的排名 (Node(r,_,_))=r 有趣的链接(t1 作为节点(r,x1,c1),t2 作为节点(_,x2,c2))= 如果 Elem.leq(x1,x2) 然后节点 (r+1,x1,t2::c1) 否则节点 (r+1,x2,t1::c2) 有趣的 insTree (t,[])=[t] |insTree (t,ts as t'::ts')= 如果排名 t < 排名 t' 则 t::ts 否则 insTree(link(t,t'),ts') 有趣的插入 (x,ts)=insTree(Node(0,x,[]),ts) 有趣的合并(ts1,[])=ts1 |合并([],ts2)=ts2 |合并(ts1 作为 t1::ts1',ts2 作为 t2::ts2')= 如果排名 t1 < 排名 t2 则 t1::merge(ts1',ts2) 否则,如果排名 t2 < 排名 t1 则 t2::merge(ts1,ts2') 否则 mwc(链接(t1,t2),ts1',ts2') (*mwc=与进位合并*) 和 mwc (c,ts1,[])=insTree(c,ts1) |mwc (c,[],ts2)=insTree(c,ts2) |mwc (c,ts1 作为 t1::ts1', ts2 作为 t2::ts2')= 如果等级 c < 等级 t1 那么如果排名 c < 排名 t2 则 c::merge(ts1,ts2) 否则 mwc(链接(c,t2),ts1,ts2') 否则 mwc(链接(c,t1),ts1',ts2) 结尾
证明 Okasaki 的实现是 O(log n):如果进位是“昂贵的”(需要一个或多个链接),那么它会产生零。因此,下一个昂贵的进位将在到达该点时停止。因此,传播所有进位所需的链接总数不超过传播前二进制表示的总长度,该长度以 ceil(log n) 为界,其中 n 是较大堆的大小。