我理解priorityQueue
Array
在List
上是完美的,因为它的性质已经到位。
我应该在OCaml中的列表上实现PriorityQueue(堆)吗?
如果我在in-place
上执行此操作,那么我必须删除every time
内容并想办法fundamental
在每个步骤中创建新列表。所以我想知道它是否值得。
实际上,我对此有更深入的思考。
因此,许多in-place
算法/数据结构是从invented
发明的(我使用not-in-place
因为我了解许多就地可以转换为FL
)。
但是,mutable
不推荐in-place / mutable
件事。我还有一个问题是如何在OCaml中immutable
和list
?或之间进行选择,何时应该在array
和{{之间选择? 1}}吗
例如,在上面的priorityqueue
案例中,如果我被要求在OCaml中写一个priorityqueue
,我是否应该更喜欢array
,因为它更自然,更容易,或者我应该为了不变而选择列表?
答案 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标准库已经有几个使用自平衡二分查找树的数据结构 - Set
和Map
,它们被实现为不可变的功能数据结构。对于大多数操作,自平衡二进制搜索树提供与二进制堆相同的时间复杂度(删除min元素和添加元素;对于两个结构都是O(log n))。峰值min元素的峰值效率较低(二进制堆的O(1);树的O(log n)),但这通常不会自己使用。使用Set
的一个问题是它不允许重复的元素;理想情况下,你会想要一个“multiset”,但OCaml在标准库中没有;如果您不关心重复元素,那么这不是问题。
我建议不要使用list
。