quickperm算法的clisp实现

Clisp implementation of quickperm algorithm

我正在研究 n 皇后问题的迭代解决方案。我决定将状态 space 表示为 0 和 1 的数组,这样 1 就代表女王的存在。计划是生成数组的所有排列,然后编写一个验证器来修剪不正确的解决方案。我正在尝试这样做是常见的 lisp,即使我在今天之前从未接触过函数式编程。

为了生成排列,我选择使用第一个伪代码示例尝试并实现此算法:http://www.quickperm.org/

这是我的尝试:

(defun permute (n)
  (setf total (* n n)) 
  (let ((a (make-array total :initial-element 0))      ;list of objects to permute
       (p (make-array total :initial-element 0)))     ;array to control iteration 
    (dotimes (i n) (setf (aref a i) 1))
    (loop for index from 1 while (< index total) do
      (setf (aref p index) (- (aref p index) 1))      ;decrement p[i] by 1
      (if (= (rem index 2) 1)                         ;if index is odd
          (setf j (aref p index))                     ;j = p[index]
          (setf j 0))                                 ;else j = 0
      (rotatef (aref a index) (aref a j))             ;swap a[index] & a[j]
      (setf index 1)                                  ;index = 1 
      (loop while (= (aref p index) 0) do             ;while p[index] == 0
        (setf (aref p index) index)                   ;p[index] = i
        (setf index (+ index 1)))                     ;index++
      print a)))           
(permute 4)

目前,我收到错误:AREF: index -1 for #array,这似乎是由 (setf (aref p index) (- (aref p index) 1)) 行引起的。在伪代码中,该行似乎实现了 p[index] = p[index] - 1。这是我唯一的减法操作,但它不应该对索引本身进行操作,而只是对其所在位置的值进行操作。

我错过了什么?

编辑:我将 p 的每个元素初始化为 0。每个元素实际上应该等于它的索引。将 post 完成后更新代码。

这是最终产品,以防哪天有什么伤心的事情在这里跌跌撞撞。

(defun permute (n) 
  (let ((a (make-array n))                            ;list of objects to permute
       (p (make-array (+ 1 n))))                      ;array to control iteration 
    (dotimes (i n) (setf (aref a i) (+ i 1)))
    (dotimes (i (+ n 1)) (setf (aref p i) i)) 
    (setf index 1)
    (loop while (< index n) do
      (setf (aref p index) (- (aref p index) 1))      ;decrement p[i] by 1
      (if (= (rem index 2) 1)                         ;if index is odd
          (setf j (aref p index))                     ;j = p[index]
          (setf j 0))                                 ;else j = 0
      (rotatef (aref a index) (aref a j))             ;swap a[index] & a[j]
      (setf index 1)                                  ;index = 1 
      (loop while (= (aref p index) 0)  do            ;while p[index] == 0
        (setf (aref p index) index)                   ;p[index] = i
        (setf index (+ index 1)))                     ;index++
      (verif a n))))

好久没写 CL 了,这里有一个使用了一些惯用形式的版本。

(defun permute (n) 
  (let ((a (make-array n))                        ;list of objects to permute
       (p (make-array (1+ n))))                   ;array to control iteration 
    (dotimes (i n) (setf (aref a i) (1+ i)))
    (dotimes (i (1+ n)) (setf (aref p i) i))
    (setf i 1)
    (loop with i = 1 and j = 0 while (< i n) do
      (decf (aref p i))                           ;decrement p[i] by 1
      (setf j (if (oddp i) (aref p i) 0))         ;j = odd(i) ? a[i] : 0
      (rotatef (aref a i) (aref a j))             ;swap a[i] & a[j]
      (setf i 1)                                  ;i = 1 
      (loop while (zerop (aref p i)) do           ;while p[i] == 0
        (setf (aref p i) i)                       ;p[i] = i
        (incf i))                                 ;index++
      (verif a n))))