我正在OCaml中实现一个binary heap
使用列表,只是为了提高我的OCaml技能。
我觉得使用列表非常困难,经过2天的努力,我必须到这里寻求建议和提示。
显然,我不能使用orignal array based
算法来使用list来实现它。
我想要利用的是binary tree
。我保持invariant
节点应该比任何级别低于它的节点大。
我粗略地想出了如何实现insert
,虽然我不确定它是否正确。
对于二叉树,每个节点都有two children
,value
和 size n
,这是offsprings
的总数。此n
用于平衡树。
插入x
时,我会与节点(来自root,递归)进行比较。假设x < the value of the node
,然后
如果节点的一个或两个孩子都是Leaf
,那么我将x
插入到该Leaf位置。
如果节点的子节点的none
为Leaf,那么我将选择n小于recursively insert
的子节点。
type 'a heap =
| Node of 'a * 'a heap * 'a heap * int
| Leaf
exception EmptyHeapException
let create_heap () = Leaf;;
let rec insert x = function
| Leaf -> Node (x, Leaf, Leaf, 0)
| Node (v, l, r, n) ->
let (stay, move) = if x > v then (x, v) else (v, x)
in
match (l, r) with
| (Leaf, Leaf) ->
Node (stay, Node (move, Leaf, Leaf, 0), Leaf, 1)
| (Leaf, _) ->
Node (stay, Node (move, Leaf, Leaf, 0), r, n+1)
| (_, Leaf) ->
Node (stay, l, Node (move, Leaf, Leaf, 0), n+1)
| (Node (_, _, _, n1), Node (_, _, _, n2)) ->
if n1 <= n2 then
Node (stay, (insert move l), r, n1+1)
else
Node (stay, l, (insert move r), n2+1);;
好的,我有以下问题。
get_top
功能的困境。我不知道如何继续。任何提示?答案 0 :(得分:3)
这个插入代码对我来说非常好看。 (我对这些计数感到困惑了一段时间,但现在我看到他们正在计算后代的数量。)
删除最大元素(根)的功能基本上是删除,这总是最难的。实质上,您需要合并两棵树,同时保持您的不变性。我现在没有时间详细研究它,但我认为这将成为可能。
如果你看看冈崎(如果你被卡住就可以做到!)你会看到他的树有一个额外的不变量,这使得更容易做这些操作。我很确定这不是我马上想出来的。他的实现基于合并两棵树的操作。它用于插入和删除。
快速浏览一下电池堆代码是基于“二叉树”,实际上要复杂得多。他们在冈崎也有解释。
<强>更新强>
Okasaki的书纯功能数据结构是他博士论文的详细阐述。似乎优先级队列只出现在书中 - 抱歉。如果你真的对FP很感兴趣并且没有太多现金,这本书真的值得拥有。
正如我所说,你的插入代码看起来很棒。在我看来,你实际上有两个不变量:
节点中的值小于或等于其子树根的值(排序不变量)。
节点的子树种群最多相差1(余额不变)。
正如我所说的,我没有时间详细验证,但它看起来像你的插入代码维护不变量,因此是O( log n )。
此结构的有用性取决于您是否能够在保留这两个不变量的同时删除O( log n )中的根。
删除草图将是这样的:
let pop = function Leaf -> 0 | Node (_, _, _, p) -> p
let rec merge a b =
(* populations of a, b differ by at most one. pop a >= pop b *)
match a, b with
| Leaf, Leaf -> Leaf
| Leaf, _ -> b
| _, Leaf -> a
| Node (av, al, ar, ap), Node (bv, bl, br, bp) ->
if av >= bv then Node (av, merge al ar, b, ap + bp)
else Node (bv, merge al ar, insert av (delete_min b), ap + bp)
and delete_min = function
| Leaf -> Leaf
| Node (_, Leaf, Leaf, _) -> Leaf
| Node (_, l, Leaf, _) -> l
| Node (_, Leaf, r, _) -> r
| Node (_, l, r, _) ->
if pop l >= pop r then merge l r else merge r l
我仍然没有太多时间,因此可能需要对正确性或复杂性进行修复。
<强>更新强>
作为一个纯粹的大脑家伙,我(真的)从未想过Chris Okasaki在现实生活中的样子。他在西点军校教书,在那里找到他的个人页面并不太难。它可能会满足你的一些好奇心。