仕事に疲れたら、人生に疲れたら、素数を数えたり、基礎的なアルゴリズムを復習したり、単純な計算問題を手で解いたりしてみるといい(線形代数の行列演算とか)。
その一環で今日はクイックソートをEmacs Lisp で作成。
(lexical-let*)
というマクロで思い通りのクロージャが作れるので、それほど煩雑にはならない。
ついでに、リストだけでなく、Vector 型に対応したものも作ってみた。
また、テストデータの作成ですこしだけ loopマクロを使った。
;; ふつうのクイックソート(リストを昇順ソート) ;; ピボットを左端の要素とする方式 (defun qsort (lat) (if (null lat) nil (lexical-let* ((piv (car lat)) (right (cdr lat)) (fn (lambda (a) (< a piv))) ) (append (qsort (remove-if-not fn right)) (list piv) (qsort (remove-if fn right)) )))) => qsort ;; Vectorを昇順ソート("elt", "vconcat", "subset"などの組み込み関数を利用) ;; ピボットを中央の要素とする方式 (defun vqsort (v) (cond ((zerop (length v)) nil) ((= 1 (length v)) v) (t (lexical-let* ((m (/ (length v) 2)) (piv (elt v m)) (v2 (vconcat (subseq v 0 m) (subseq v (1+ m)))) (fn (lambda (a) (< a piv)))) (vconcat (vqsort (remove-if-not fn v2)) (vector piv) (vqsort (remove-if fn v2))) )))) => vqsort ;; 実行してみる(リストのソート) ;; (loop ...)は 30 から 1 までの数を要素とするリストを生成 (qsort (loop for i from 30 downto 1 append (list i)) ) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30) ;; 実行してみる(vectorのソート) ;; (loop ...)は 30 から 1 までの数を要素とするvectorを生成 (vqsort (loop for i from 30 downto 1 with v do (setf v (vconcat v (vector i))) finally (return v) )) => [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30]
結果を見る限り、正しくできたと思われる。
0 件のコメント:
コメントを投稿