[英]Slow 'quick sort' in clojure
我在clojure中編寫了一個快速排序功能,但運行速度非常慢。 有時,如果輸入集合變得更大,它甚至可能會溢出堆棧?
我的代碼有問題嗎?
(defn qsort [coll]
(if (<= (count coll) 1)
coll
(let [pivot (last coll)
head-half (filter #(< % pivot) (drop-last coll))
tail-half (filter #(>= % pivot) (drop-last coll))]
(concat (qsort head-half) (vector pivot) (qsort tail-half)))))
我也閱讀了clojure.core中的sort函數,但使它感到困惑。
01 (defn sort
02 "Returns a sorted sequence of the items in coll. If no comparator is
03 supplied, uses compare. comparator must
04 implement java.util.Comparator."
05 {:added "1.0"
06 :static true}
07 ([coll]
08 (sort compare coll))
09 ([^java.util.Comparator comp coll]
10 (if (seq coll)
11 (let [a (to-array coll)]
12 (. java.util.Arrays (sort a comp))
13 (seq a))
14 ())))
唯一發生遞歸的地方是第12行。它只是交換兩個輸入參數! 您能否向我解釋為什么運行這段代碼?
(. java.util.Arrays (sort a comp))
此調用是對Arrays排序函數的,而不是對clojure.core排序函數的遞歸調用。
您的代碼很慢,因為快速排序是imperative algorithm
即它基於命令式編程的概念,例如就地數組變異。 您的代碼很好,但是問題是它遍歷了集合多次,並且還創建了許多中間集合。
您可以使用數組和就地數組突變來快速進行快速排序。
Clojure的sort函數僅在內部使用Java的標准java.util.Arrays / sort方法; 這不是100%Clojure的實現。
Quicksort並不是習慣性Clojure的真正匹配,因為它取決於具有快速O(1)元素交換的集合類型。 還要注意,在實現中,您在每次調用時都執行(last coll)和(count coll),其中coll是一個惰性序列,所以兩者都是O(n)-您應該能夠通過提高性能來提高性能考慮到〜可能是通過使用Java Array而不是不可變的seq作為中間集合類型。
堆棧溢出的問題是您將遞歸過濾器遞歸地放置在過濾器上。 這在這里很好地解釋了:
關於另一個問題:在第12行中,這不是對clojure sort函數的調用,而是對Arrays-sort函數的調用。 在用戶代碼中,通常會編寫(java.util.Arrays/sort a comp)
而不是點語法。
您的qsort可能會花費大部分時間分配對象。
雖然我認為您的版本讀起來更好
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.