[英]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那樣的東西。
順便說一下,Rosetta Code有一個列表迭代冒泡排序的例子,所以我不會復制它。 相反,下面是一個遞歸版本,我改編自Prolog版本(羅馬巴塔克)。 因此它不一定更好,但它使用多個值, 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 (ij (+ 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
但首先,我們不需要使用預測。 大多數循環結構對它們迭代的代碼都有隱含的預測
(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是多余的你可以將已分類的聲明移動到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出現在函數調用位置。 出現在表單前面的任何內容都必須是一個函數。 在這個cas LIS中是一個參數。
幸運的是,Common Lisp有一個內置函數,可以為我們交換值 - 它叫做rotatef。 因此,entires形式需要看起來像
(rotatef (nth I lis) (nth (1+ i) lis))
我會考慮一下你的算法。 正如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.