在Clojure中天真快速排序

时间:2011-07-25 12:13:34

标签: clojure quicksort

我正在学习clojure,并希望我的天真快速排序。此实现将数组(向量)减半并以递归方式处理它们。问题是,当递归结束时数组(向量)的大小为1时,此代码会抛出NullPointerException。那是为什么?

(ns qsort)

(defn qsort [arr] 
(println "arr" arr)
(def cnt (count arr))
(def pivotidx (if (> cnt 1)
  (int (/ cnt 2))
  -1
))

(print "pivotidx:" pivotidx " ")
(if (> pivotidx -1)
  ((def pivotval (nth arr pivotidx))
  (println "pivotval:" pivotval " ")
  (def right (filter #(> % pivotval ) arr))
  (def left (filter #(< % pivotval) arr))
  (println "left" left "right" right)
  (concat (qsort left) [pivot] (qsort right))
  )
  arr
)
) 


(defn sortme [] (qsort [3 5 8 9 1 7 12 13 2 14 0]))

4 个答案:

答案 0 :(得分:4)

其他答案已经很好地描述了“正确”的做事方式,巧合的是也解决了你的问题。但是,您的NPE是由

引起的
((def pivotval (nth arr pivotidx))
 ...more stuff...)

您不能简单地使用()对元素进行分组:lisp中的(foo)表示调用函数foo;同样,((bar) (foo))表示:

  1. 致电bar,将结果保存为x
  2. 致电foo。将结果保存为y
  3. 使用参数x
  4. 调用函数y

    因为def没有返回函数,所以用六个或七个参数调用它的结果会导致问题。

    相反,如果您想要分组内容,则应使用do特殊表单。 (do (foo) (bar))表示“调用foo,然后返回调用bar的结果”。

答案 1 :(得分:2)

正确使用let代替def是正确的事情:

(defn qsort [arr]
(println "arr" arr)
(let 
 [
  cnt (count arr)
  pivotidx (if (> cnt 1) (int (/ cnt 2)) -1)
 ]
(print "pivotidx:" pivotidx " ")

(if (> pivotidx -1) 
 (let
   [
    pivotval (nth arr pivotidx)
    right (filter #(> % pivotval ) arr)
    left (filter #(< % pivotval) arr)
   ] 
 (println "pivotval:" pivotval " ")
 (println "left" left "right" right)
 (concat (qsort left) [pivotval] (qsort right))
 )
 arr) ))

然后

(qsort [3 5 8 9 1 7 12 13 2 14 0])

返回:

(0 1 2 3 5 7 8 9 12 13 14)

答案 2 :(得分:1)

(defn qsort
  [l]
  (cond
    (empty? l) '()
    :else (let [f (first l)
                smaller (filter #(<= % f) (rest l))
                bigger (filter #(> % f) (rest l))]
            (concat (qsort smaller) [f] (qsort bigger)))))

答案 3 :(得分:0)

如果数组长度为1,则表示如下:

  • pivotidx将为0
  • pivotval将是第一个(唯一)项
  • 因此左右都是空的(无)
  • 因此你会在下一次递归时得到一个空指针异常(可能是当你试图计算nil的长度时....)

要修复的一些提示/其他错误

  • 将测试用于nil或空列表在函数的开头
  • 不要在函数中使用def - 使用(让[name value] ...)而不是
  • 我认为你的分区逻辑会错过重复的重点 - 检查这个案例!
  • 不确定为什么要将数据透视值放在数组的中间,通常最简单的方法就是使用(第一个arr)作为数据透视表。您想要选择中间值的唯一情况是您知道数据已经接近排序....