我正在尝试在 Common Lisp 中实现冒泡排序,但我很难确定自己的方位。[见下文]是我到目前为止所得到的,据我所知,它遵循算法,但是我收到错误“使用参数 () 调用未定义的函数 SORTED”。当我运行它时。我似乎找不到这是什么原因。
(defun bubble (lis)
(let ((sorted nil) (j 0))
(do () ((not sorted))
(progn
(setf sorted t)
(do (i j (+ i 1))
(if (< (nth i lis) (nth (+ i 1) lis))
(progn
(swap1 (lis (nth i lis) (nth (+ i 1) lis)))
(setf sorted nil)
)
)
)
)
)
)
)
每次调用
NTH
都需要迭代列表。如果将列表视为向量,则可能应该使用向量。如果您并不真正关心效率,您可能仍然想使用 ELT
而不是 NTH
,因为 ELT
适用于任何类型的序列。这样,您可以传递向量或列表,并且至少其中一个可以很好地工作(就冒泡排序的效率而言)。
您最终可能会得到类似于Rosetta Code中的东西。
顺便说一下,Rosetta Code 有一个列表迭代冒泡排序的例子,所以我就不复制了。相反,下面是我根据 Prolog 版本(由 Roman Barták)改编的递归版本。因此,它不一定更好,但它使用多个值,
ETYPECASE
,DESTRUCTURING-BIND
,...显然通常不教授的功能。
(defun bubble-sort (list)
(labels
((bsort (list acc)
(etypecase list
(null acc)
(cons (destructuring-bind (head . tail) list
(multiple-value-bind (new-tail max)
(bubble head tail)
(bsort new-tail
(cons max acc)))))))
(bubble (x list)
(etypecase list
(null (values nil x))
(cons (destructuring-bind (y . tail) list
(multiple-value-bind (new-tail max)
(bubble (max x y) tail)
(values (cons (min x y) new-tail)
max)))))))
(bsort list nil)))
我们可以做很多事情来改进这段代码。
您可以采取一些措施来改善您的问题。如果您再次询问,请提供测试用例和具体问题。
缩进
Lisp 的语法相对较少,但我们使用缩进来帮助突出代码的结构。大多数了解 Lisp 的编辑器都会帮助管理这个问题。与传统缩进方法最明显的不同是下面几行的右括号。我缩进了 mergelist 函数以显示更易读的函数体 - 嗯,至少对我来说是这样。
(defun bubble (lis)
(let ((sorted nil) (j 0))
(do () ((not sorted))
(progn
(setf sorted t)
(do (i j (+ i 1))
(if (< (nth i lis) (nth (+ i 1) lis))
(progn
(swap1 (lis (nth i lis) (nth (+ i 1) lis)))
(setf sorted nil))))))))
循环与DO
DO 在 lisp 中有着悠久的血统,但说实话,我用 DO 总是犯错误,所以不经常使用它。我永远不记得返回表格去哪里,增量。我倾向于使用LOOP
但首先,我们不需要使用 progn。大多数循环结构对于它们正在迭代的代码都有一个隐式 progn,所以
(defun bubble-1 (lis)
(let ((sorted nil) (j 0))
(do () ((not sorted))
(setf sorted t)
(do (i j (+ i 1))
(if (< (nth i lis) (nth (+ i 1) lis))
(swap1 (lis (nth i lis) (nth (+ i 1) lis)))
(setf sorted nil))))))
稍微好一点。查看您的代码,其中有对 swap1 的调用,它必须是某处提供的 defun 。此行还存在语法问题,因为“lis”显示为函数调用。
让我们尝试评估该函数,看看会发生什么
; in: DEFUN BUBBLE-1
; (LET ((SORTED NIL) (J 0))
; (DO ()
; ((NOT SORTED))
; (SETF SORTED T)
; (DO (I
; J
; (+ I 1))
; (IF (< # #) (SWAP1 #) (SETF #)))))
;
; caught STYLE-WARNING:
; The variable J is defined but never used.
; in: DEFUN BUBBLE-1
; (DO (I
; J
; (+ I 1))
; (IF
; (< (NTH I LIS) (NTH (+ I 1) LIS))
; (SWAP1 (LIS (NTH I LIS) (NTH # LIS)))
; (SETF SORTED NIL)))
; --> BLOCK
; ==>
; (LET (I J (+ I))
; (TAGBODY
; (GO #:G3)
; #:G2
; (TAGBODY)
; (PSETQ + 1)
; #:G3
; (UNLESS IF (GO #:G2))
; (RETURN-FROM NIL (PROGN (< # #) (SWAP1 #) (SETF #)))))
;
; caught WARNING:
; undefined variable: I
; --> BLOCK LET TAGBODY UNLESS
; ==>
; (IF IF
; NIL
; (GO #:G2))
;
; caught WARNING:
; undefined variable: IF
; (LIS (NTH I LIS) (NTH (+ I 1) LIS))
;
; caught STYLE-WARNING:
; undefined function: LIS
; (SWAP1 (LIS (NTH I LIS) (NTH (+ I 1) LIS)))
;
; caught STYLE-WARNING:
; undefined function: SWAP1
;
; compilation unit finished
; Undefined functions:
; LIS SWAP1
; Undefined variables:
; I IF
; caught 2 WARNING conditions
; caught 3 STYLE-WARNING conditions`enter code here`
哇。这告诉我们一些事情
嵌套循环中的 DO 语法是错误的。它需要是一般形式
(DO ((var init step))
(termination-test result-form)
statement)
嵌套 do 缺少终止测试。此外,i 的变量声明缺少初始化。
Let有点多余,你可以将sorted的声明移到do中
(do ((sorted nil)) ((not sorted ) ... )
表格
(SWAP1 (LIS (NTH I LIS) (NTH (+ I 1) LIS)))
有两个问题。首先 SWAP1 未定义。其次,形式 (LIS (NTH I LIS) (NTH (+ I 1) LIS)) 不可能是正确的,因为 LIS 出现在函数调用位置。出现在表单前面的任何内容都必须是函数。在这种情况下,LIS 是一个参数。
幸运的是,Common Lisp 有一个内置函数,可以为我们交换值 - 它称为rotatef。所以整个表格需要看起来像
(rotatef (nth I lis) (nth (1+ i) lis))
我会考虑一下你的算法。正如 Zephyr Pellerin 上面所说,递归解决方案会更好,所以除非您的任务是使用迭代解决方案
您应该研究 David Hodge 的答案,其中详细介绍了代码的所有问题。在这里,我提供了使用
do
特殊形式的冒泡排序的迭代版本。与您尝试用代码实现的算法的唯一主要区别是使用变量 end
,该变量每次都会递减以减少测试数量:
(defun bubble (lis)
(let ((sorted nil)
(end (length lis)))
(do () (sorted lis)
(setf sorted t)
(decf end)
(do ((i 0 (1+ i)))
((>= i end))
(when (< (nth i lis) (nth (1+ i) lis))
(rotatef (nth i lis) (nth (1+ i) lis))
(setf sorted nil))))))
(defun bubble_move (l)
(cond
((atom (cdr l)) l)
((> (car l) (cadr l)) (cons (cadr l) (bubble_move (cons (car l) (cddr l)))))
(T l)
)
)
(defun bubble (l)
(cond
((atom (cdr l)) l)
(T (bubble_move (cons (car l) (bubble (cdr l)))))
)
)
(bubble '(5 4 3 2 1))
很久以前写这个只是为了好玩,但偶尔发现你的问题