我的Quicksort无法使用负数(Common Lisp)

时间:2013-08-30 09:02:25

标签: types lisp common-lisp quicksort negative-number

该功能只有正数才能正常工作。工作有时是负面但大部分时间显示此错误“值-1不是UNSIGNED-BYTE类型”。

(defun OrdRapido (lista inf sup)
  (let ((pivote (nth sup lista)) (i (1- inf)) (j sup) (aux))
    (unless (>= inf sup)
        (loop (when (>= i j) (return))
          (loop (setf i (1+ i)) (when (>= (nth i lista) pivote) (return)))
          (loop (setf j (1- j)) (when (<= (nth j lista) pivote) (return)))
          (when (< i j)
            (setf aux (nth i lista))
            (setf (nth i lista) (nth j lista))
            (setf (nth j lista) aux)))  
        (setf aux (nth i lista))
        (setf (nth i lista) (nth sup lista))
        (setf (nth sup lista) aux) 
        (OrdRapido lista inf (1- i))
        (OrdRapido lista (1+ i) sup)) 
    lista)) 

例如:

(setq lista2 '(-5 3 7 6 2 1 -4 100 5 80 96 14 2 3 1 0 0 789 -1 3))
(OrdRapido lista2 0 (1- (length lista2)))

CL-USER> 
(-5 3 7 6 2 1 -4 100 5 80 96 14 2 3 1 0 0 789 -1 3)
CL-USER> 
(-5 -4 -1 0 0 1 1 2 2 3 3 3 5 6 7 14 80 96 100 789)

但不适用于此,我只添加 - 到80

'(-5 3 7 6 2 1 -4 100 5 -80 96 14 2 3 1 0 0 789 -1 3)

由于

更正版本(添加了随机数据),我知道有更好的方法,这只是一个专业人员留下的练习

 (defun OrdRapido (lista inf sup)
  (let ((pivote (nth (random (1+ sup)) lista)) (i inf) (j sup) (aux))
    (unless (>= inf sup)
        (loop (when (> i j) (return))
          (loop (when (<= (nth i lista) pivote) (return)) (setf i (1+ i)))
          (loop (when (>= (nth j lista) pivote) (return)) (setf j (1- j)))
          (when (<= i j)
            (setf aux (nth i lista))
            (setf (nth i lista) (nth j lista))
            (setf (nth j lista) aux)
            (setf i (1+ i))
            (setf j (1- j))))  
        (OrdRapido lista inf j)
        (OrdRapido lista i sup)) 
    lista))

3 个答案:

答案 0 :(得分:6)

您正在尝试返回列表中不起作用的第-1个元素。 nth返回列表的第n个元素,因此(nth 0'(1 2 3))将返回1.但是在代码中的某个时刻它会调用(nth -1(-5 -80 -4 -1 0 0 ... ))和繁荣!

有关您的代码的其他说明:

  • 将结束语放在单独的行上并不是好的lisp风格,并且使您的代码更难阅读。 Lisp代码由列表组成,parens并不像其他语言的花括号。
  • 使用支持您语言的编辑器。我推荐带有Slim的Vim或带有粘液的Emacs。如果您使用带有粘液this video may help you get started的电子邮件。
  • 不要在你的名字中使用骆驼套管。当它们被实习时,所有符号都会在常见的lisp中上升,因此'HelloThere 'hellothere 'HELLOTHERE <完全相同的符号 /强>

另外请查看at the rosettacode page以获取quicksort以查看如何在common-lisp(以及许多其他语言)中执行此操作。

;; Here is a functional version for example.
(defun quicksort (list &aux (pivot (car list)) )
  (if (rest list)
      (concatenate 'list 
             (quicksort (remove-if-not #'(lambda (x) (< x pivot)) list))
             (remove-if-not #'(lambda (x) (= x pivot)) list)
             (quicksort (remove-if-not #'(lambda (x) (> x pivot)) list)))
      list))

如果您不习惯阅读lambdas,那么这里的代码与上面的代码相同,但将lambdas编译成本地函数,因此代码读起来更像英语。

(defun quicksort (list &aux (pivot (car list)))
  (labels ((less-than-pivot (x) (< x pivot))
           (greater-than-pivot (x) (> x pivot))
           (equal-to-pivot (x) (= x pivot)))
    (if (rest list)
        (concatenate 'list 
                     (quicksort (remove-if-not #'less-than-pivot list))
                     (remove-if-not #'equal-to-pivot list)
                     (quicksort (remove-if-not #'greater-than-pivot list)))
        list)))

第二个版本在我的脑海里不那么整洁。在这两个示例中,您可以看到递归方法如何让您考虑如何只执行一个步骤,然后通过调用自身将一个步骤应用于解决整个问题的解决方案

答案 1 :(得分:1)

仅仅因为您最初的想法是使用loop执行此操作。以下是您可能已经完成的工作:

(defun quicksort (list)
  (if (cdr list)
      (loop :with pivot := (car list)
         :for element :in list
         :if (< element pivot) :collect element :into a
         :else :if (= element pivot) :collect element :into b
         :else :collect element :into c
         :finally (return (nconc (quicksort a) b (quicksort c)))) list)) 

答案 2 :(得分:1)

禁止编译器技巧,NTH需要O(i)时间来访问列表的第i个元素,因为它必须遍历列表中的每个元素直到那一点。这意味着仅使用NTH访问列表的每个元素将花费O(n ^ 2)时间。由于快速排序应该在O(nlgn)时间内执行,因此需要稍作改动。

当您走到列表并通过该尾部而不是使用NTH访问剩余的尾部时,您可以快速排序列表。由于lisp列表是单独链接的,因此还必须仅向前移动列表。

(defun simple-list-partition (list end)
  "Reorder list until end such that all values less than the first value in the
  list are placed left of it and all greater placed to its right; return the new
  index of the first value and the tail of the list starting with that value as
  multiple values."
  (loop for walk-cons on (cdr list)
        for walk-value = (car walk-cons)
        for walk-index from 1
        with pivot-value = (car list)
        with rotate-cons = list
        with rotate-index = 0
        while (<= walk-index end)
        when (< walk-value pivot-value)
        do (progn (setq rotate-cons (cdr rotate-cons)
                        rotate-index (+ 1 rotate-index))
                  (rotatef (car rotate-cons) (car walk-cons)))
        finally (progn (rotatef (car list) (car rotate-cons))
                       (return (values rotate-index rotate-cons)))))

(defun quicksort (list)
  "Quicksort for lists."
  (labels ((quicksort% (l  max)
             (when (and (plusp max) (cdr l))
               (multiple-value-bind (index tail)
                   (simple-list-partition l max)
                 (quicksort% l (1- index))
                 (quicksort% (cdr tail) (- max index 1))))))
    (quicksort% list (1- (length list)))
    list))

为简单起见,上述内容并不能防止预分类或相同元素的列表性能不佳。