【问题标题】:OutOfMemoryError in lazy-seq [duplicate]惰性序列中的 OutOfMemoryError [重复]
【发布时间】:2012-12-27 00:26:35
【问题描述】:

可能重复:
Recursive function causing a stack overflow

处理示例lazy-seq here

(defn sieve [s]
  (cons (first s)
        (lazy-seq (sieve (filter #(not= 0 (mod % (first s)))
                             (rest s))))))

如果我尝试生成超过几千个左右的素数,我会收到 OutOfMemoryError。根据我的研究(但我对clojure 很陌生),我怀疑这可能是“抓住头”类的问题,但无法弄清楚为什么会这样或如何补救。在生成大量素数时如何更改此函数以免内存不足?

【问题讨论】:

标签: clojure


【解决方案1】:

您可以在不创建惰性序列的情况下使用版本。它运行得更快、更便宜:

 (defn sieve* [res s]
      (if (empty? s)
        res
        (recur (conj res (first s))
               (filter #(not= 0 (mod % (first s)))
                       (rest s)))))

(defn sieve [n]
  (sieve* [] (range 2 n)))

(sieve 10000)
=> [2 3 5 7 11 13 17 ... 9941 9949 9967 9973]

这是更高效的版本:

(defn sieve* [res n maxn]
  (if (> n maxn)
    res
    (if (some #(= 0 (mod n %))
              (take (round (sqrt (count res))) res))
      (recur res (inc n) maxn)
      (recur (conj res n) (inc n) maxn))))

(defn sieve [n]
  (sieve* [] 2 n))

(last (sieve 1000000))
=> 999983

更新。相当快/便宜的懒惰版本

(defn primes-seq* [primes]
  (let [last-prime (last primes)]
    (cons last-prime
          (lazy-seq
           (primes-seq*
            (conj primes
                  (first (let [compare-primes
                               (take (round (sqrt (count primes)))
                                     primes)]
                           (drop-while (fn [n]
                                         (some #(= 0 (mod n %))
                                               compare-primes))
                                       (iterate inc (inc last-prime)))))))))))


(def primes-seq (primes-seq* [2]))

(last (take 50000 primes-seq))
=> 611953

【讨论】:

  • 我更喜欢惰性解决方案,谢谢。
  • @richguy 没问题。我添加了惰性版本。
【解决方案2】:

给定的算法通过“记住”所有先前的素数来工作,所以如果你继续运行足够长的时间,你将会破坏堆栈。

以下可能效率较低但不会耗尽内存(改编自我的4clojure解决方案#116):

(defn prime-seq []
  (letfn [(is-prime [x]
            (not (some #(= (rem x %) 0) (range 2 x))))]
    (filter is-prime (range))))

(take 20 (prime-seq))
;=> (0 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61)
(nth (prime-seq) 10000)
;=> 104723

【讨论】:

  • 这行得通,但正如你所说的那样很慢。
猜你喜欢
  • 2014-06-23
  • 1970-01-01
  • 2014-11-10
  • 2016-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-01
  • 2011-07-21
相关资源
最近更新 更多