Last active
August 29, 2015 13:58
-
-
Save kohyama/10232624 to your computer and use it in GitHub Desktop.
Sort algorithms in Clojure
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (defn insertion-sort [ks] | |
| (reduce (fn [a x] | |
| (let [[h t] (split-with #(< % x) a)] | |
| (concat h [x] t))) | |
| [] ks)) | |
| (defn merge-sort [ks] | |
| (let [c (count ks)] | |
| (if (= c 1) ks | |
| ((fn m [[[ah & ar :as a] [bh & br :as b]]] | |
| (cond (nil? ah) b | |
| (nil? bh) a | |
| (< ah bh) (cons ah (m [ar b])) | |
| :else (cons bh (m [a br])))) | |
| (map merge-sort (split-at (quot c 2) ks)))))) | |
| (defn quick-sort [[k & ks]] | |
| (if (nil? k) [] | |
| (apply #(concat %1 [k] %2) | |
| (map quick-sort | |
| (reduce (fn [[a b] x] | |
| (if (< k x) [a (conj b x)] [(conj a x) b])) | |
| [[] []] ks))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
整列アルゴリズム in Clojure
挿入ソート
[]で累積器aを空ベクタで初期化し,シーケンス
ksの要素をxで順に参照して,reduceで累算します.各回で, 累積器
aはそれまでに参照した値が整列された状態で格納されているベクタになるようにします.(split-with #(< % x) a): 累積器aの中身を先頭から見て行き, 最初にx以上の値が見つかった場所未前と, それ以後の二つのシーケンスに分割します.let [[h t] ...]: 前者をh, 後者をtとして,(concat h [x] t):h,[x]およびtを連結して新しい累積器の値とします.これによって, 整列済みである状態を保持して累積器のシーケンスに要素
xを追加できました.[x]は要素xだけからなるベクタです.(split-with #(< % x) a)は, 1パスで[(take-while #(< % x) a) (drop-while #(< % x) a]と同等の動作を行います.マージソート
let [c (count ks)]: 対象のシーケンスの長さをcとします.if (= c 1) ks: 長さが 1 ならば整列済みとして与えられたシーケンスそのまま返します.(split-at (quot c 2) ks): 対象のシーケンスを半分の長さで分割します.(map merge-sort ...): それぞれをマージソートします.((fn m [...] ...) ...): 以下の処理をmとし, ソート済みの二つのシーケンスに適用します.[[ah & ar :as a] [bh & br :as b]]: 二つのソート済みシーケンスをそれぞれa,bとします. その際,aの先頭の要素をah, 残りのシーケンスをarとします.bも同様です.(nil? ah) b:ahが nil, つまりaが空ならば,bが全体の整列結果です.(nil? bh) a:bhが nil, つまりbが空ならば,aが全体の整列結果です.(< ah bh) (cons ah (m [ar b]):ahがbhより小さければ,arを新しいa,bを新しいbとして処理mを行った結果の先頭にahを追加したものが全体の整列結果です.:else (cons bh (m [a br])):ahがbh以上ならば,aを新しいa,brを新しいbとして処理mを行った結果の先頭にbhを追加したものが全体の整列結果です.クイックソート
先頭の要素を
k, 残りのシーケンスをksとします.ksを,k以下の要素のシーケンスと,kより大きい要素のシーケンスに分割します.[(remove #(< k %) ks) (filter #(< k %) ks)]でも構いませんが, 2パスを嫌って,1パスで
とします.
map quick-sortで, 両方のシーケンスをクイックソートし,apply #(concat %1 [k] %2)で, 前者のシーケンス%1,kだけからなるシーケンス[k]および後者のシーケンス%2を連結します.実行例
注意
アルゴリズム実装の演習のためか特殊な条件下以外では, 整列には組込の
sort関数を用いてください.アルゴリズムに焦点をあてるため, 対象は
<で比較可能なオブジェクトのシーケンスとしました.実利用する場合は, 引数に, オブジェクトを比較するための関数を与えることができるようにして, 且つその比較関数のデフォルトを
compareにします.また, 対象が大きくてもスタックが溢れないためには, 再帰呼出し箇所に lazy-seq を用いた方が良いかもしれません.
Clojure 演習