Functional programming 我应该在OCaml中的列表上实现优先级队列(Heap)吗?

Functional programming 我应该在OCaml中的列表上实现优先级队列(Heap)吗?,functional-programming,ocaml,Functional Programming,Ocaml,我知道priorityQueue在Array上是完美的,因为它的性质是合适的 我应该在OCaml中的列表上实现优先级队列(堆)吗? 如果我在列表上执行此操作,那么我必须删除中的内容,并想办法每次都在每个步骤中创建一个新列表。所以我想知道这是否值得 事实上,我对此有更深入的思考 因此,许多基本算法/数据结构是从就地发明的(我使用发明的,因为我知道许多就地可以转化为不就地) 但是,FL不推荐可变的东西。我的另一个问题是如何在就地/可变和不可变之间进行选择?或在OCaml中,何时应该在列表和数组之间

我知道
priorityQueue
Array
上是完美的,因为它的性质是合适的

我应该在OCaml中的列表上实现优先级队列(堆)吗?

如果我在
列表
上执行此操作,那么我必须删除
中的
内容,并想办法每次都
在每个步骤中创建一个新列表。所以我想知道这是否值得


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

因此,许多
基本算法/数据结构是从
就地
发明的(我使用
发明的
,因为我知道许多就地可以转化为
不就地

但是,
FL
不推荐
可变的东西。我的另一个问题是如何在
就地/可变
不可变
之间进行选择?或在OCaml中,何时应该在
列表
数组
之间进行选择?



例如,在上面的
priorityqueue
案例中,如果我被要求在OCaml中编写
priorityqueue
,我应该更喜欢
array
,因为它更自然、更容易,还是我应该选择list以实现不可变?

使用不可变数据在模块性和可靠性方面具有惊人的优势。本质上,数据不可能通过其他模块的修改而损坏。模块不再需要担心其他模块以及谁“拥有”数据。直到你不再需要做这件事,你才会意识到这有多么繁重。另一个意想不到的好处是,对代码的行为进行推理变得更加容易,因为它的行为就像一个数学函数。我在实践中经历过这两种情况,这使我成为了FP的信徒。成本通常惊人地低,要么是一个小的常数因子,要么是一个额外的对数n

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

也就是说,我有时确实使用可变数据,因为它可以更快


作为元注释,我建议您花一些时间在OCaml中只使用不可变数据。如果没有其他东西的话,它一开始是一个非常有趣的谜题。在一些直接的经验之后,你将能够判断在特定情况下的权衡。因此,我建议您尝试实现一个不可变优先级队列(或者阅读其他人是如何实现的)。

电池在这里有一个有效的功能堆:find_min为O(1),所有其他堆操作都是log(n)

我相信实现是一个标准的二项式堆,如Okasaki所述。请看这里:

但是,如果您仍然坚持使用具有破坏性操作的堆,那么我认为core的实现是从.NET中剽窃的。你得仔细看看

更重要的是,我同意Jeffrey的观点,并建议您首先真正熟悉功能数据结构,并且仅在绝对必要时使用命令式数据结构。我相信这之前已经向您提出过,但这类信息的最佳来源是冈崎的纯函数数据结构书。我极力推荐它

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

优先级队列的另一种选择是使用自平衡二叉搜索树;OCaml标准库已经有了几个使用自平衡二叉搜索树--
Set
Map
的数据结构,它们被实现为不可变的功能数据结构。对于大多数操作(remove-min-element和add-element;这两种结构都是O(logn)),自平衡二进制搜索树提供了与二进制堆相同的时间复杂性。它对于最小化最小元素(二进制堆为O(1);树为O(logn))效率较低,但它本身通常不会使用。使用
Set
的一个问题是它不允许重复元素;理想情况下,您需要一个“多集”,但OCaml在标准库中没有一个;如果您不关心重复的元素,那么这不是问题


我不建议为此使用
list

好的,我同意你关于不可变的好处的看法。我只是想知道,比如说,如果面试官让我用OCaml写一个priorityqueue,我应该更喜欢数组,因为它更自然、更简单,或者,为了保持不变,我应该选择列表?
我应该如何回答?或者,使用列表并使用原始/标准算法实现优先级队列是否值得?我认为跳过学习部分,直接跳转到面试答案是没有意义的!他们问的原因是他们想听听你学到了什么。你可以两个都试一下,看看他们的表现如何。我的一般回答是,除非我有充分的理由不这样做,否则我会使用不变的数据。如果有人正在雇佣OCaml程序员,他们可能会对是否熟悉不可变数据感兴趣。但我只是一个有一定经验的人。你能告诉我我应该使用列表实现堆,还是使用原始的二进制堆算法(这对就地数组来说是最好的)?我会说你应该同时做这两件事,是的,尽管很难想象你为什么想知道我对它的看法!:-)如果你不想工作,你