在SML中实现更快的Fifo

时间:2019-04-24 22:04:10

标签: sml mutable smlnj

是否可以实现Fifo,以支持其功能的子集,即仅EnqueueDequeueisEmpty,以及使用常规{{ 1}}对象,使用某种可变的指针,这样就不会在当前的两列表实现使用的某些时间产生复制一个列表的开销(当复杂度被摊销时,这没有,因为它仍然是O(1)摊销的运营成本,但仍不足以满足我的一项应用程序的要求),如果是,那么精确度如何?

1 个答案:

答案 0 :(得分:0)

您可以将Array用于dynamic array solution,这也将产生摊销成本,或者您可以使用ref和{{1}来实施doubly-linked lists }类型。我已经链接到C解决方案,因为这样的解决方案在SML中虽然语法上更复杂,但它们是相似的,并且因为我在SML中找不到任何示例。双链列表解决方案在装入每个节点时将产生内存开销,但不会产生动态阵列解决方案或您描述的功能齐全的双端队列的摊销成本。

功能性双端队列已成为许多研究的主题; this Wikipedia article中有一些关于数个数据结构和方法的参考,它们都依赖于惰性而不是惰性。我不知道它们中的任何一个都是 O(1);看来它们都是 O(1)摊销后的或 O(lg n),但仍然很有效。

以下是非功能性双向链接列表数据类型的样子:

option

这种实现方式有一些缺点:

  • 对引用的跟踪在语法上不是很好。您可以在C语言中编写

    datatype 'a node = Node of { elem : 'a
                               , prev : 'a node option ref
                               , next : 'a node option ref
                               }
    
    datatype 'a deque = Empty | NonEmpty of 'a node
    

    ,但这在SML中看起来更加晦涩难懂,除非您定义了一系列用于获取和设置上一个/下一个节点的辅助函数。即使这样做,由于不常用引用,因此与C的指针语法不同,您的getter和setter看起来将是非标准的。

  • 您正在重新发明空指针。实现本身很脆弱,因为您可能会遇到上一个节点/下一个节点在不应该引用if (nd->prev) nd->prev->next = nd; 的情况。这些操作不会超出推,弹出,移位和不移位的范围,因此在完成这些操作后,您可以依靠测试(基于单元或基于属性)。我要说,您绝对必须进行测试,而不是购买ML通常利用的优势。

  • 您的队列是可变的,因此现在您必须小心传递队列。如果您对队列的使用进入中断状态,那么您将很难找到导致该队列的源。您基本上是用较丑陋的语法编码C。

因此,简短的答案是:您绝对可以编写相同的实现,但是该语言并不鼓励这样做,并且函数式程序员经常依赖于对数或摊销运行时间的不可变数据结构。