簡體   English   中英

Clojure中的“快速排序”緩慢

[英]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可能會花費大部分時間分配對象。

  • 過濾器的調用為每個遍歷的每個數字分配一個lazy-cons實例
  • 串聯的調用為每個數字分配另一個對象

雖然我認為您的版本讀起來更好

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM