クイックソートを C言語と Go言語で実装してみました。クイックソートは、配列の中からひとつ任意にサンプルを取ってきます。これを「ピボット」といいます。あとは、配列からピボットを除いたものを、その値がピボットより大きいか小さいかで二つの配列に分け、さらにその二つを再帰的にクイックソートします。最後はそれらを「小、ピボット、大」の順に連結します。これだけです。
C言語。じつは最初は自力で実装しようとしたのですが、うまい方法がどうしても思いつきませんでした。で、アルゴリズムの教科書を参照してみたのですが、配列の分割にとても巧みな方法が採用されていて、びっくりしました。下の partition() ですね。クイックソートは C でこんなに簡単に実装できるのだな。いや、まいりました。
quick_sort.c
#include <stdio.h> int partiton(int ar[], int p, int r) { int x, i, j, tmp; x = ar[r]; i = p - 1; for (j = p; j < r; j++) { if (ar[j] <= x) { i++; tmp = ar[i]; ar[i] = ar[j]; ar[j] = tmp; } } ar[r] = ar[i + 1]; ar[i + 1] = x; return i + 1; } void quick_sort(int ar[], int p, int r) { if (p < r) { int q = partiton(ar, p, r); quick_sort(ar, p, q - 1); quick_sort(ar, q + 1, r); } } int main() { int ar[] = {3, 1, 5, 2, 9, 7, 0}; int len = sizeof ar / sizeof(int); quick_sort(ar, 0, len - 1); printf("["); for (int i = 0; i < len; i++) { printf("%d, ", ar[i]); } printf("\b\b]\n"); return 0; }
Go言語。Cとはまったくちがう実装ですが、これも大変にシンプルに実装できます。クイックソートは優秀なソート法として知られますが、実装も簡単なのがすばらしいですね。
Go は append() 関数があるのがラクでいいですね。Go でスライスを扱うには、append() の挙動を正確に理解しておくことが重要だと思います。
quick_sort.go
package main import "fmt" func quick_sort(ar []int) []int { var left, right []int if len(ar) > 1 { x := ar[0] for _, a := range ar[1:] { if a < x { left = append(left , a) } else { right = append(right, a) } } left = quick_sort(left) right = quick_sort(right) ar = append(append(left, x), right...) } return ar } func main() { ar := quick_sort([]int{3, 1, 5, 10, 2, 9, 7, 0}) fmt.Println(ar) }
ちなみに Ruby だとこんな感じです。実質 3行。Go言語版とやっていることは同じです。何というか、アルゴリズムがそのままコードになっているという印象ですね。
class Array def quick_sort return [] if empty? x, xs = first, drop(1) xs.select{|i| i < x}.quick_sort + [x] + xs.select{|i| i >= x}.quick_sort end end
アルゴリズムイントロダクション 第3版 第1巻: 基礎・ソート・データ構造・数学 (世界標準MIT教科書)
- 作者: T.コルメン,R.リベスト,C.シュタイン,C.ライザーソン,浅野哲夫,岩野和生,梅尾博司,山下雅史,和田幸一
- 出版社/メーカー: 近代科学社
- 発売日: 2012/08/02
- メディア: 単行本
- 購入: 1人 クリック: 16回
- この商品を含むブログ (20件) を見る