在clojure中的惯用选择排序

时间:2015-06-25 04:16:09

标签: clojure

我试图在clojure中实现选择排序O(n2)。是的,底层排序使用非常有效的java的数组排序。然而,这是一项学习练习。

下面的代码有效,但是我想知道是否有一种更惯用的重写方式,因为下面看起来很笨重 -

(defn mins [coll]
  (reduce (fn[[min-coll rest-coll] val]
            (case (compare val (first min-coll))
              -1 [[val] (apply conj rest-coll min-coll)]
              0 [(conj min-coll val) rest-coll]
              1 [min-coll (conj rest-coll val)]))
          [[(first coll)] []]
          (rest coll)))

;; (mins [3 1 1 2]) => [[1 1] [3 2]]

(defn selection-sort [coll]
  (loop [[sorted coll] [[] coll]]
    (let [[s c] (mins coll)]
      (if-not (seq coll)
        sorted
        (recur [(concat sorted s) c])))))

(selection-sort [3 1 1 2 5 7 8 8 4 6])

2 个答案:

答案 0 :(得分:1)

功能性解决方案可能是:

(defn selection-sort
  [input]
  (let [ixs (vec (range (count input)))
        min-key-from (fn [acc ix] (apply min-key acc (subvec ixs ix)))
        swap (fn [coll i j] (assoc coll i (coll j) j (coll i)))]
    (reduce
     (fn [acc ix] (swap acc ix (min-key-from acc ix))) input ixs)))

答案 1 :(得分:0)

您可以使用以下内容:

(defn remove-first [coll e]
  (if-let [pos (and (seq coll) (.indexOf coll e))]
      (vec (concat 
            (subvec coll 0 pos) 
            (subvec coll (inc pos))))
      coll))

(defn best [coll f]
  (reduce f
          (first coll)
          (rest coll)))

(defn select-sort 
  ([coll] (select-sort coll min))
  ([coll fmin]
   (loop [sorted (transient []) c (vec coll)]
     (if (seq c)
       (let [n (best c fmin)]
         (recur (conj! sorted n) (remove-first c n)))
       (persistent! sorted)))))

 => (select-sort [3 5 2])
 => [2 3 5]

 => (select-sort [3 5 2] max)
 => [5 3 2]