Common Lisp代码冻结或需要优化

时间:2017-10-19 15:02:34

标签: algorithm performance optimization lisp common-lisp

我目前正在处理Project Euler中的一些问题,这是我的Common Lisp学习例程的一部分。我不会提到它与该网站的精神一致的问题。

我遇到的问题是我的代码适用于小输入但冻结大输入。具体来说,它冻结了获得答案所需的相同数量级,但成功运行的数量级低于该数量级。

问题描述如下:给定一组数字,形成这些数字的所有可能的排列,然后用数字排序结果并选择结果集的第n个成员。

我会按如下方式运行以下代码。

例如,如果我想获得数字(1, 2, 3)的第三个排列,我会打电话:

CL-USER> (number-permutations '(1 2 3) 3) 213

另一个例子是:

CL-USER> (number-permutations '(0 1 2 3 5) 100) 50231

代码适用于此:

CL-USER> (number-permutations '(0 1 2 3 5 6 7 8) 100) 1283675

但冻结(或花费太长时间)此电话:

CL-USER> (number-permutations '(0 1 2 3 5 6 7 8 9) 1000000)

我的问题是双重的。我做得不好,导致计算花费这么长时间?我是否遇到了Lisp实现(SBCL)的一些限制?如何才能在合理的时间内完成计算?

代码:

;;; How to make permutations of a list
;;;
;;;   all permutations of a list L is:
;;;   for each element E in L:
;;;   that element prepended to all permutations of [ L with E removed ]
(defun permutation (digits)
  ;if the list is null or empty, return NIL
  (cond ((null digits) nil)
    ;if the list consists of one element, return the list of one element
    ((null (cdr digits)) (list digits))
    ; cycle through every element in list and append            
        ; that element to all permutations of a list of elements
    ; with the current element removed
    (t (loop for element in digits
          append (mapcar (lambda (l) (cons element l))
                 (permutation (remove element digits)))))))

(defun list-to-number (list)
  (loop for item in list for i from (- (list-length list) 1) downto 0
        summing (* (expt 10 i) item)))

(defun number-permutations (digits n)
  (car (nthcdr (- n 1)
         (sort (loop for item in (permutation digits)
                     collecting (list-to-number item))
               #'<))))

1 个答案:

答案 0 :(得分:3)

正如High Performance Mark的评论所述,所以可以关闭此问题:

我做得不好,导致计算花费这么长时间?
您进行n!次计算,n为多位数。 1000000!大约等于8.26×10 5565708 (请参阅Quora以获得一个很好的解释),所以难怪你的计算机无法处理它;)

我是否遇到了Lisp实现(SBCL)的一些限制?
也许,但你的RAM很可能首先失败。

可以采取哪些措施让计算在合理的时间内完成?
做另一个计算。项目欧拉演习的重点通常是找到一种解决问题的聪明方法,而不是强力解决问题。

祝你好运!