繁体   English   中英

冒泡排序常见的Lisp错误

[英]Bubble Sort Common Lisp Error

我正试图在Common Lisp中实现冒泡排序,而且我很难掌握我的方向。[见下文]是我到目前为止所得到的,据我所知,它遵循算法,但我'得到错误“用arguments()调用未定义函数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那样的东西。

顺便说一下,R​​osetta Code有一个列表迭代冒泡排序的例子,所以我不会复制它。 相反,下面是一个递归版本,我改编自Prolog版本(罗马巴塔克)。 因此它不一定更好,但它使用多个值, ETYPECASEDESTRUCTURING-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)))

我们可以做很多事情来改进这段代码。

你可以采取一些措施来改善你的问题。 如果再问一次,请提供测试用例和具体问题。

  1. 缩进

    Lisp的语法相对较少,但我们使用缩进来帮助突出显示代码的结构。 大多数支持Lisp的编辑都有助于管理它。 与传统缩进方法最明显的不同之处是关闭以下几行括号。 我缩进了mergelist函数来显示一个更易读的函数体 - 好吧,至少对我而言。

     (defun bubble (lis) (let ((sorted nil) (j 0)) (do () ((not sorted)) (progn (setf sorted t) (do (ij (+ i 1)) (if (< (nth i lis) (nth (+ i 1) lis)) (progn (swap1 (lis (nth i lis) (nth (+ i 1) lis))) (setf sorted nil)))))))) 
  2. 循环与DO

DO在lisp中有很长的血统,但说实话,我总是在DO中犯错,所以不要经常使用它。 我永远不会记得返回表格的位置,增量。 我倾向于使用LOOP

但首先,我们不需要使用预测。 大多数循环结构对它们迭代的代码都有隐含的预测

(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`

哇。 这告诉我们一些事情

  1. 不使用嵌套DO中的变量J. 去掉它。
  2. 嵌套循环中DO的语法是错误的。 它必须是一般形式

     (DO ((var init step)) (termination-test result-form) statement) 

嵌套的do缺少终止测试。 i的变量声明也缺少初始化。

  1. Let是多余的你可以将已分类的声明移动到do中

     (do ((sorted nil)) ((not sorted ) ... ) 
  2. 表格

     (SWAP1 (LIS (NTH I LIS) (NTH (+ I 1) LIS))) 

有两个问题。 首先,SWAP1未定义。 其次,形式(LIS(NTH I LIS)(NTH(+ I 1)LIS))可能不正确,因为LIS出现在函数调用位置。 出现在表单前面的任何内容都必须是一个函数。 在这个cas LIS中是一个参数。

幸运的是,Common Lisp有一个内置函数,可以为我们交换值 - 它叫做rotatef。 因此,entires形式需要看起来像

(rotatef (nth I lis) (nth (1+ i) lis))
  1. 一旦函数运行,它在do中没有结果形式,因此排序的数组永远不会返回给调用者。 你将看不到输出。 你需要考虑这里嵌套循环的事实。

我会考虑一下你的算法。 正如Zephyr Pellerin所说,递归解决方案会更好,所以除非你的任务是使用迭代解决方案

您应该研究David Hodge的答案,其中详细说明了代码的所有问题。 在这里,我提供了一个使用do特殊形式的Bubble Sort的迭代版本。 与您尝试使用代码实现的算法的唯一主要区别是使用变量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)))))) 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM