在lisp中修改quicksort以使用中间评估器过滤器

时间:2017-05-07 10:15:31

标签: sorting common-lisp quicksort

我正致力于实施使用中间评估函数的快速排序;不是测试函数,而是一个估价器,用于替换数字在其他上下文中表示的间接值。

我在所有情况下都无法工作,感觉我已经碰到了一堵砖墙。我的主要目的是按照距离相机的距离对一组中的三角形进行排序(数组是唯一面的索引之一,估值器函数查找给定索引的网格面,然后返回相机的距离) ),但为了简洁起见,我将在下面使用一个更简单的例子。这是Common Lisp中的quicksort- *代码:

(defun quicksort-* (arr lo hi &key (valuator #'identity))
  (declare (type (simple-array fixnum (*)) arr)
           (type fixnum lo hi)
           (type function valuator))
  (flet ((%partition (arr p r)
           (declare (type (simple-array fixnum (*)) arr)
                    (type fixnum p r))
           (let ((x (funcall valuator (aref arr p)))
                 (i (1- p))
                 (j (1+ r)))
             (loop do
                   (loop do
                         (decf j)
                         until (<= (funcall valuator (aref arr j)) x))
                   (loop do
                         (incf i)
                         until (>= (funcall valuator (aref arr i)) x))
                   (if (< i j)
                       (rotatef (aref arr i) (aref arr j))
                     (return-from %partition j))))))
    (when (< lo hi)
      (let ((p (%partition arr lo hi)))
        (quicksort arr lo p)
        (quicksort arr (1+ p) hi))))
  arr)

那究竟会是什么呢?

鉴于

(defparameter *names* #("Earl" "Dudley" "Chuck" "Bob" "Alice"))

和我们想要排序的列表,目前随机加扰为

(defparameter *nameindices* '(2 4 0 1 3))

使用谓词函数&#39; namevaluator&#39;在 nameindices 上运行quicksort- *:

(defun namevaluator (nameindex)
   (let ((sortednames (sort (copy-seq *names*) #'string>)))
      (position (aref *names* nameindex) sortednames :test #'string=)))

因此应该产生#(4 3 2 1 0)以反映下降排序的名称,对吗?

CL-USER> (quicksort
           *nameindices*
            0 (1- (length *nameindices*))
            :valuator
            #'namevaluator)
#(0 1 2 3 4)
嗯,不,不。但是,嘿,至少它仍然排序,即使是相反的。

当然,改变#&#39; string&gt;到#&#39;字符串&lt;在namevaluator函数中应该产生#(4 3 2 1 0)然后,对吗?嗯......不,这就成了答案:

#(1 2 3 4 0)

在%分区函数中翻转&gt; =和&lt; =符号并不会产生更好的结果(并且这可能不是太热的想法);它仍会导致一个结果被排序,另一个结果不按顺序。

我想在%分区中插入一个funcall-predicate测试,它最初只是简单地评估了普通整数值,因为比较只会简单地“工作”。实际上,使用默认的#&#39; IDENTITY函数作为评估器,它确实:

(let ((random-numbers (coerce (loop repeat 30 collect (random 1000)) 'vector)))
   (quicksort-* random-numbers 0 (1- (length random-numbers))))

> #(29 91 121 130 191 228 250 382 392 406 443 468 468 480 535 555 576 597 598 604 635 646 646 685 712 721 724 764 849 860)

也许答案就在我的鼻子底下,但我还没有看到它?

1 个答案:

答案 0 :(得分:4)

(a)如果递归调用函数,则使用名称quicksort,但函数名称为quicksort- *。我错过了什么吗?

(b)您在顶级调用中传递自定义求值程序,但在递归调用中不这样做,因此对于那些#&#39;身份是有效的。您可以尝试使用标签函数进行递归,这样您就不必重新说明:估价器了。