algorithm - clojure中的列表处理,需要尾递归

标签 algorithm clojure functional-programming tail-recursion

给定一个排序的间隔列表,例如 (def lst (list [7 10] [32 35]))

我需要实现一个向列表中添加新间隔的函数。如果新区间与列表中的任何区间相邻,则应合并它们:

(= (add-range [1 3] lst)   (list [1 3] [7 10] [32 35]))  ;; prepend left
(= (add-range [1 6] lst)   (list [1 10] [32 35]))        ;; merge left
(= (add-range [11 20] lst) (list [7 20] [32 35]))        ;; merge right
(= (add-range [11 31] lst) (list [7 35]))                ;; merge left and right

这是我的实现:

(defn add-range
  [range range-list]
  (if (empty? range-list)
    (list range)
    (let
      [lo (first range)
       hi (second range)
       head (first range-list)
       head-lo (dec (first head))
       head-hi (inc (second head))]
        (if (< hi head-lo)
          (cons range range-list)
          (if (= hi head-lo)
            (cons [lo (second head)] (rest range-list))
            (if (= lo head-hi)
              (recur [(first head) hi] (rest range-list))
              (cons head (add-range range (rest range-list)))))))))

它看起来也很优雅,但最后一行包含一个递归调用 add-range 不能用 recur 替换,因为它不是最后一次调用.我计划在我的应用程序中使用长范围列表,我不想炸毁堆栈。

如何使用尾递归重写它? 有没有另一种方法来解决这个问题?可能是惰性序列?

更新 实际上不需要排序列表。这可以是一个集合,甚至是一个未排序的列表,但一次完成它会非常好。

最佳答案

使用排序集,您可以将其实现为:

;; first the constructor
(defn ranges [& rs]
  (apply sorted-set-by
    (fn [[from-a to-a] [from-b to-b]]
      (< to-a (dec from-b))) rs))

;; then add-range itself
(defn add-range [ranges [from to :as r]]
  (let [rs (subseq ranges <= [from from] <= [to to])
        ranges (reduce disj ranges rs)]
    (conj ranges
      (let [[from'] (or (first rs) r)
            [_ to'] (or (last rs) r)]
        [(min from from') (max to to')]))))

让我们试试你的测试:

=> (def lst (ranges [7 10] [32 35]))
#'user/lst
=> (add-range lst [1 3])
#{[1 3] [7 10] [32 35]}
=> (add-range lst [1 6])
#{[7 10] [32 35]}
=> (add-range lst [11 20])
#{[7 20] [32 35]}
=> (add-range lst [11 35])
#{[7 35]}

附录 #1:add-range 是 O((m + 1) log n),其中 n 是范围集的大小,m 是合并区间的数量。

关于algorithm - clojure中的列表处理,需要尾递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32520176/

相关文章:

haskell - 在 Haskell 中推导是什么/意味着什么?

java - 正确使用 Guava 两种类型的谓词

algorithm - HSL插值

clojure - 围绕 lein 的困惑 :dependencies and :plugins

algorithm - 使用具有重复值的中序和预序构造二叉树

Clojure-New Cond 宏?

Clojure文件系统的可移植性

c++ - 默认情况下,如何使函数指针参数无操作?

algorithm - 有效的时间表算法

java - 这个 Stacked Number 生成代码有什么问题?