我正在尝试将队列实现为双向链表。但是,当我尝试将第二个节点排入队列时,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
答案 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)
然后再试一次。
位样式指南: