1

我想计算diskc的移动次数。但相反,结果我得到了别的东西。

(setq x 0)

(defun towersOfHanoi (n from to help)
  (if (> n 0)
   ;progn evaluates multiple forms and returns the result from the last one.*/
   (progn
     (towersOfHanoi (- n 1) from help to)
     (format t "~d ----> ~d~%" from to)
     (towersOfHanoi (- n 1) help to from)
     (+ 1 x)
     )  

    ))



;(towersOfHanoi 3 'A 'B 'C)

当我运行它时,我得到

(towersOfHanoi 3 'A 'B 'C)
A ----> B
A ----> C
B ----> C
A ----> B
C ----> A
C ----> B
A ----> B
1

为什么它是 1 而不是 7,我猜每次递归调用都会将 x 的值重置为 0,但是,我怎样才能获得磁盘的移动次数。谢谢。

4

1 回答 1

4

在 lispif中最多需要三个参数;条件,条件为真时评估的形式,以及条件为假时评估的形式。

详情请参阅http://www.lispworks.com/documentation/HyperSpec/Body/s_if.htm

为了评估一个分支中的多个表单,您可以使用progn它评估多个表单并返回最后一个表单的结果。

此外,princ期望只打印一个参数。为了一次打印几件东西,您可以使用format

在您的情况下(还要注意括号的位置):

(defun towersOfHanoi (n from to help)
 (if (> n 0)
   (progn
     (towersOfHanoi (1- n) from to help)
     (format t "~d ----> ~d~%" from to)
     (towersOfHanoi (1- n) help to from))))

没有错误分支,您也可以使用whenthat 可以评估多个形式:

(defun towersOfHanoi (n from to help)
  (when (> n 0)
    (towersOfHanoi (1- n) from to help)
    (format t "~d ----> ~d~%" from to)
    (towersOfHanoi (1- n) help to from)))

为了计算移动,您可以使用局部计数变量(用 引入let)和更新此变量的内部工作函数(用 引入labels):

(defun towers-of-hanoi (n &optional (from 1) (to 2) (help 3))
  (let ((counter 0))                                          ; local variable
    (labels ((towers-of-hanoi-core (n from to help)           ; local function
               (when (> n 0)
                 (towers-of-hanoi-core (1- n) from to help)
                 (incf counter)                        
                 (format t "~d ----> ~d~%" from to)
                 (towers-of-hanoi-core (1- n) help to from))))
      (towers-of-hanoi-core n from to help))                  ; leave work to inner function
    (format t "Moves: ~d ~%" counter)))

在这里,from、to 和 help 也是可选的,默认为 1、2 和 3。

再次:详细信息可在 Hyperspec 中找到:http ://www.lispworks.com/documentation/HyperSpec/Front/

于 2013-01-20T10:34:46.777 回答