Clojure 中的不可变队列

发布于 2024-09-07 13:32:30 字数 199 浏览 8 评论 0原文

在 Clojure 中获取简单、高效的不可变队列数据类型的最佳方法是什么?

它只需要两个操作,即使用通常语义的入队和出队。

我当然考虑了列表和向量,但我知道它们在末尾和开头的修改分别具有相对较差的性能(即 O(n) 或更差) - 因此对于队列来说并不理想!

理想情况下,我想要一个适合入队和出队操作的 O(log n) 的持久数据结构。

What is the best way to obtain a simple, efficient immutable queue data type in Clojure?

It only needs two operations, enqueue and dequeue with the usual semantics.

I considered lists and vectors of course, but I understand that they have comparatively poor performance (i.e. O(n) or worse) for modifications at the end and beginning respectively - so not ideal for queues!

Ideally I'd like a proper persistent data structure with O(log n) for both enqueue and dequeue operations.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你与昨日 2024-09-14 13:32:30

问题已解决 - 为其他可能认为有帮助的人提供解决方案。

我发现 Clojure 有 clojure.lang.PersistentQueue 类可以完成所需的工作。

您可以创建这样的实例:

(def x (atom clojure.lang.PersistentQueue/EMPTY))

据我所知,您当前需要使用 Java 互操作来创建实例,但正如 Michal 指出的那样,您随后可以使用 peek、pop 和 conj。

Problem solved - solution for others who may find it helpful.

I've found that Clojure has the clojure.lang.PersistentQueue class that does what is needed.

You can create an instance like this:

(def x (atom clojure.lang.PersistentQueue/EMPTY))

As far as I can see, you currently need to use the Java interop to create the instance but as Michal helpfully pointed out you can use peek, pop and conj subsequently.

勿忘初心 2024-09-14 13:32:30

我使用以下函数queue来创建一个PersistentQueue。或者,如果您要打印和读取队列,您可能需要一个打印方法和一个数据读取器。

通常的 Clojure 函数已经为 PersistentQueue 实现了。

  • peek -- 获取头部
  • pop -- 返回一个没有头部的新 PersistentQueue
  • conj -- 将项目添加到尾部为
  • 空? -- 如果为空则为 true
  • seq -- 内容为序列(列表)

    (defn queue
      ([] clojure.lang.PersistentQueue/EMPTY)
      ([coll] (reduce conj clojure.lang.PersistentQueue/EMPTY coll)))

    (defmethod print-method clojure.lang.PersistentQueue
      [q ^java.io.Writer w]
      (.write w "#queue ")
      (print-method (sequence q) w))

    (comment
       (let [*data-readers* {'queue #'queue}]
         (read-string (pr-str (queue [1 2 3])))))

I use the following function queue to create a PersistentQueue. Optionally, you might want to have a print-method and a data-reader if you're going to be printing and reading the queues.

The usual Clojure functions are already implemented for PersistentQueue.

  • peek -- get the head
  • pop -- returns a new PersistentQueue without the head
  • conj -- add item to the tail
  • empty? -- true if empty
  • seq -- contents as a sequence (list)

    (defn queue
      ([] clojure.lang.PersistentQueue/EMPTY)
      ([coll] (reduce conj clojure.lang.PersistentQueue/EMPTY coll)))

    (defmethod print-method clojure.lang.PersistentQueue
      [q ^java.io.Writer w]
      (.write w "#queue ")
      (print-method (sequence q) w))

    (comment
       (let [*data-readers* {'queue #'queue}]
         (read-string (pr-str (queue [1 2 3])))))
生死何惧 2024-09-14 13:32:30

Clojure 确实可以从队列文字中受益。这比依赖 Java 互操作更干净(并且更可移植)。

然而,创建自己的便携式持久队列并不难,只需使用列表等普通家庭用品即可。

将队列视为两个列表,一个提供队列的头部,另一个提供队列的尾部。 enqueue 添加到第一个列表,dequeue 从后者弹出。大多数ISeq 函数都是简单实现的。

也许唯一棘手的部分是当尾部为空并且您想要出队时会发生什么。在这种情况下,头列表将被reversed并成为新的尾部,而空列表将成为新的头列表。我相信,即使有反向的开销,enqueuedequeue仍然是O(1),不过当然,k 会比普通向量更高。

快乐排队

Clojure could really benefit from a queue literal. This would be cleaner (and more portable) than relying on Java interop.

However, it's not that hard to roll your own portable persistent queue, just using ordinary household items like lists.

Consider the queue as two lists, one providing the head portion of the queue, and the other the tail. enqueue adds to the first list, dequeue pops from the latter. Most ISeq functions are trivially implemented.

Probably the only tricky part is what happens when the tail is empty and you want to dequeue. In that case the head list is reversed and becomes the new tail, and the empty list becomes the new head list. I believe, even with the overhead of the reverse, that enqueue and dequeue remain O(1), though the k is going to be higher than a vanilla vector of course.

Happy queueing!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文