我应该在OCaml中的List上实现PriorityQueue(Heap)吗?

时间:2013-03-01 18:01:20

标签: functional-programming ocaml

我理解priorityQueue ArrayList上是完美的,因为它的性质已经到位。

我应该在OCaml中的列表上实现PriorityQueue(堆)吗?

如果我在in-place上执行此操作,那么我必须删除every time内容并想办法fundamental在每个步骤中创建新列表。所以我想知道它是否值得。


实际上,我对此有更深入的思考。

因此,许多in-place算法/数据结构是从invented发明的(我使用not-in-place因为我了解许多就地可以转换为FL)。

但是,mutable不推荐in-place / mutable件事。我还有一个问题是如何在OCaml中immutablelist之间进行选择,何时应该在array和{{之间选择? 1}}吗


例如,在上面的priorityqueue案例中,如果我被要求在OCaml中写一个priorityqueue,我是否应该更喜欢array,因为它更自然,更容易,或者我应该为了不变而选择列表?

3 个答案:

答案 0 :(得分:3)

使用不可变数据可提供模块化和可靠性方面的惊人优势。实质上,通过其他模块的修改,数据不可能被破坏。模块不再需要担心其他模块,以及谁“拥有”数据。你不会意识到这是多么繁重,直到你不再需要这样做。另一个意想不到的好处是,更容易推理代码的行为,因为它就像一个数学函数。我在实践中经历过这两个,这使我成为FP的信徒。成本通常是令人惊讶的适度,要么是一个小的常数因子,要么是额外的 log n

不可变数据的另一个优点是持久性,即无需额外努力即可维护数据的历史状态的能力。 (在不可变环境中实现撤消操作很有意思。)

那就是说,我有时会使用可变数据,因为它可以更快。

作为一个元评论,我建议你花一些时间在OCaml中只使用不可变数据。如果没别的话,它最初是一个非常有趣的谜题。经过一些直接的经验,你将能够判断特定情况下的权衡取舍。所以我建议你尝试实现一个不可变的优先级队列(或者阅读其他人如何做到这一点)。

答案 1 :(得分:2)

电池在这里有一个高效的功能堆:http://ocaml-batteries-team.github.com/batteries-included/hdoc2/BatHeap.html,其中find_min为O(1),所有其他堆操作都是log(n)

我认为实现是Okasaki中描述的标准二进制堆。看看这里:https://github.com/ocaml-batteries-team/batteries-included/blob/master/src/batHeap.ml

如果你仍然坚持使用破坏性操作的堆,那么我认为核心有一个实现扯掉了.NET。你需要仔细看看。

更重要的是,我同意Jeffrey的观点,并建议您首先对功能数据结构非常熟悉,并且只在必要时才使用命令式数据结构。我确信之前已经向您建议,但这种信息的最佳来源是Okasaki的纯功能数据结构书。我不能高度推荐它。

答案 2 :(得分:2)

二进制堆(您可能正在考虑的优先级队列的实现)通常在动态数组(在某些语言中称为“向量”)上实现,即可以添加元素或者从中删除元素。 array不合适,因为它是固定大小的;它的大小在您创建时是固定的。您可以首先在array之上实现动态数组结构,然后在它之上实现二进制堆,如果您愿意的话。

优先级队列的另一个选择是使用自平衡二进制搜索树; OCaml标准库已经有几个使用自平衡二分查找树的数据结构 - SetMap,它们被实现为不可变的功能数据结构。对于大多数操作,自平衡二进制搜索树提供与二进制堆相同的时间复杂度(删除min元素和添加元素;对于两个结构都是O(log n))。峰值min元素的峰值效率较低(二进制堆的O(1);树的O(log n)),但这通常不会自己使用。使用Set的一个问题是它不允许重复的元素;理想情况下,你会想要一个“multiset”,但OCaml在标准库中没有;如果您不关心重复元素,那么这不是问题。

我建议不要使用list