双链表实现中的无限递归

时间:2014-04-21 03:42:50

标签: common-lisp infinite-loop read-eval-print-loop doubly-linked-list

我正在尝试将队列实现为双向链表。但是,当我尝试将第二个节点排入队列时,enqueue函数会进入无限递归,我似乎无法弄清楚导致它的原因。

(defstruct node
  value
  (next nil)
  (previous nil))



(defstruct (queue (:print-function print-queue))
  (first nil)
  (last nil))

(defun print-queue (queue s d)
  (do ((node (queue-first queue) (node-next node)))
      ((null node) (format s "~%"))
      (format s "~A " (node-value node))))

(defun enqueue (data queue)
  (let ((node (make-node :value data)))
    (if (null (queue-first queue))
        (setf (queue-first queue) node (queue-last queue) node)
        (setf (node-previous node) (queue-last queue)
              (node-next (queue-last queue)) node
              (queue-last queue) node))))

编辑:有问题的测试用例

(setf queue (make-queue))
(enqueue 3 queue)
(enqueue 4 queue) ; this call never terminates and blows up the stack

关于CLISP的最后一个陈述导致了 * - 程序堆栈溢出。重置

在SBCL上它只是进入无限循环而我必须退出SBCL

1 个答案:

答案 0 :(得分:4)

嗯,你还没有真正看过错误。 ; - )

如果您使用SBCL:

0] backtrace

...
11898: (SB-KERNEL::%DEFAULT-STRUCTURE-PRETTY-PRINT #1=#S(NODE :VALUE 4 :NEXT NIL :PREVIOUS #S(NODE :VALUE 3 :NEXT #1# :PREVIOUS NIL)) #<SYNONYM-STREAM :SYMBOL SB-SYS:*STDOUT* {10001ACA23}>)
11899: ((LABELS SB-IMPL::HANDLE-IT :IN SB-KERNEL:OUTPUT-OBJECT) #<SYNONYM-STREAM :SYMBOL SB-SYS:*STDOUT* {10001ACA23}>)
11900: (PRIN1 #1=#S(NODE :VALUE 4 :NEXT NIL :PREVIOUS #S(NODE :VALUE 3 :NEXT #1# :PREVIOUS NIL)) NIL)
11901: (SB-IMPL::REPL-FUN NIL)
11902: ((LAMBDA NIL :IN SB-IMPL::TOPLEVEL-REPL))
11903: (SB-IMPL::%WITH-REBOUND-IO-SYNTAX #<CLOSURE (LAMBDA NIL :IN SB-IMPL::TOPLEVEL-REPL) {1002ACB00B}>)
11904: (SB-IMPL::TOPLEVEL-REPL NIL)
11905: (SB-IMPL::TOPLEVEL-INIT)
11906: ((FLET #:WITHOUT-INTERRUPTS-BODY-58 :IN SAVE-LISP-AND-DIE))
11907: ((LABELS SB-IMPL::RESTART-LISP :IN SAVE-LISP-AND-DIE))

这不是导致这种情况的功能。

正如您所看到的,在打印结果时会发生错误。您在回溯中看到函数PRIN1用于打印节点结构。您的函数已经返回了一个结果,现在需要在REPL中打印。

您的函数返回循环数据结构,Lisp尝试打印它。然后它进入无限循环。

你需要告诉Lisp,它应该处理打印机中的循环数据结构。

使用

(setf *print-circle* t)

然后再试一次。

位样式指南:

  • 通常使用CLOS类而不是结构
  • 为每个结构提供自定义打印机,尤其是具有圆形的结构
  • 从函数中返回有意义的结果