【问题标题】:A double ended queue in OCaml - what's the idea?OCaml 中的双端队列 - 这是什么想法?
【发布时间】:2015-11-27 16:14:33
【问题描述】:

我遇到了这种双端队列的实现:

type 'a elem = { mutable l1 : 'a elem; mutable l2 : 'a elem; v : 'a option }
type 'a queue = { mutable front : 'a elem; mutable back : 'a elem }

let init () =
    let rec g1 = { l1 = g1; l2 = g2; v = None}
    and     g2 = { l1 = g2; l2 = g1; v = None}
    in
        { front = g1; back = g2 }

let is_empty q =
    let f = q.front
    and b = q.back
    in
        f.l2 == b

let put_between p q x =
    let r = { l1 = p; l2 = q; v = Some x }
    in begin
        if p.l1 == q then p.l1 <- r else p.l2 <- r;
        if q.l1 == p then q.l1 <- r else q.l2 <- r
    end

我真的不明白这个实现的主要思想是什么,主要概念是什么?你能给我解释一下吗?为什么我们使用这些记录相互递归?

【问题讨论】:

  • 它看起来像一个带有两个前哨节点的双向链表。这两种记录类型虽然不是相互递归的 - elem 是递归的,但没有引用 queue

标签: ocaml deque imperative-programming


【解决方案1】:

稍微扩展一下@Lee 所说的,这是双端队列(或双端队列)的简单可变实现,就像您用普通指针(如C)用语言编写的代码一样。

除了保持链接直通之外,我只能看到一些具体的想法。

  1. 双端队列的每一端都有一个标头(@Lee 称之为哨兵)。所以一个空的双端队列中有两个节点。由于双向联动,每个节点都指向另一个节点。 (这可能是您所指的递归。)

  2. 因为 OCaml 是强类型的,所以所有节点都必须是相同的类型,即使是末尾的标头。由于标头中没有值,因此您需要使用 'a option 作为值。换句话说,您需要允许其中没有任何值的节点。

  3. put_between 的调用者需要提供两个相邻节点,但它们可以按任意顺序提供。

  4. 代码使用“物理相等”(==) 来测试节点的身份。这在 OCaml 中是一件危险的事情,但在这里是正确的。可变值可以与== 进行比较,其结果或多或少与您在命令式语言中比较指针所期望的结果相同。

学习 OCaml 的一个原因是学习函数式编程。这段代码对此没有用,因为(正如我所说)它是一个 mutable 实现。您可以在Chris Okasaki's PhD thesis 的第 5 章中看到一些实际的函数式双端队列实现。 (你也可以买他的书,这是常年的最爱。)

【讨论】:

  • 但是为什么我们使用四个链接:front.l1front.l2back.l1back.l2。在纯 C(++) 中,您只需使用两个指针 - 指向下一个和上一个元素
  • 每个节点都有另外两个节点:l1l2。有两个链接,而不是四个。队列对象 ('a queue) 包含两个标头,因此队列对象内总共有四个链接。
  • Aaaa,所以frontback 是虚拟对象,l1 是前一个节点,l2 是下一个节点?
  • 是的,这是正确的。我不会称它们为“虚拟”对象,但它们是空节点。使用标头可以稍微简化代码,尤其是在具有强类型化的 OCaml 中。 (一个空的双端队列必须与其中包含一些节点的双端队列类型相同。)
  • 好吧,但这里有些奇怪。 back 的前一个元素是 back 本身,nextfront。有什么逻辑吗?
猜你喜欢
  • 2012-11-05
  • 2021-10-12
  • 2014-11-24
  • 2020-04-19
  • 1970-01-01
  • 2014-10-14
  • 1970-01-01
  • 2012-01-27
相关资源
最近更新 更多