簡體   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