導入
「データ構造とアルゴリズム」
- 配列とコレクション
- ソート
- サーチ
- 再帰
今回はその第2回目として
実際のプログラミングでは、
展開
ソートとは
ソートとは、
- 昇順:小さいものから大きなものへ
- 降順:大きなものから小さなものへ
この連載記事において、
代表的なソートアルゴリズム
ソートを行うアルゴリズムの例として次のものが挙げられます。
- 基本形
- 基本交換法:バブルソート
- 基本選択法:直接選択法
- 基本挿入法
- 応用形
- 改良交換法:クイックソート
- 改良選択法:ヒープソート
- 改良挿入法:シェルソート
ここに紹介する分類は
基本選択法
アルゴリズムが単純で理解しやすいことから、
基本選択法のアルゴリズムは次のとおりです。
- 基本選択法のアルゴリズム
- 要素数
nの配列aにランダムな整数データが代入されているものとする。 - 添字のために整数変数
iを用意する。初期値を0とする。 - 次の手順を
iの値がn-2の時まで繰り返す。a[i]を最小値であるとする。整数変数sにiの値を代入する。a[i+1]からa[n-1]まで巡回してa[s]と比較する。a[s]より小さい要素があれば、その添字の値を整数変数 sに代入する(巡回用のカウンタ変数は jとする)。a[i]とa[s]の値を交換する。iの値を1つ増やす。
- 要素数
実際に手を動かし、
基本選択法のsketch
基本選択法ののアルゴリズムをProcessingで組んだものが次のsketchです。ソートの様子を画面に描くために、
SelectionSort.pde final int NUMBER_OF_RANDOM_DATA = 500;
final String DATA_FILE_NAME = "RandomData.txt";
final int DIAMITER = 5;
ArrayList<Integer> nums = new ArrayList<Integer>();
int i = 0; // ソート回数。drawする度にカウントアップ
void setup(){
//ランダムなデータの読み込み
loadData();
//ディスプレイウインドウの設定
size(NUMBER_OF_RANDOM_DATA,NUMBER_OF_RANDOM_DATA);
background(0,0,0);
frameRate(30);
stroke(255,0,0);
}
void loadData(){
String lines[] = loadStrings(DATA_FILE_NAME);
for(String val : lines){
nums.add(int(val));
}
}
void onePassOfSelectionSort(){
int s = i;
for(int j = i + 1; j < NUMBER_OF_RANDOM_DATA; ++j){
if(nums.get(j) < nums.get(s)){
s = j;
}
}
int t = nums.get(i);
nums.set(i,nums.get(s));
nums.set(s, t);
}
void draw(){
if (i < NUMBER_OF_RANDOM_DATA - 1){
//ソート1パス
onePassOfSelectionSort();
//結果をプロット
println("Count " + i);
clear();
for (int k=0; k < nums.size(); k++) {
ellipse(k,nums.get(k),DIAMITER,DIAMITER);
}
++i;
}
}5つのデータをソートする場合、setupメソッド内のframeRate(30)をframeRate(60)などとすると、
基本選択法の計算量
基本選択法のアルゴリズムでは、n個ある場合、n-1回の比較が行われ、n-1個のデータが残ります。次のループではn-2回の比較が行われ、n-2個のデータが残ります。こうして、
1回目のループ n-1回比較
2回目のループ n-2回比較
3回目のループ n-3回比較こうして検索回数は、nに応じた計算回数を表す関数です。
T(n) = (n-1) + (n-2) + (n-3) + ... + 2 + 1
= n (n-1) / 2
= (n2 - n) / 2この式のオーダー、nの変化に応じて急激に増加する形か、
O(n2)これは計算量としては大きい部類です。実際にコンピュータを動かした場合に大変時間がかかるということです。
改良挿入法:シェルソート
次に、
- シェルソートのアルゴリズム
- 要素数
nの配列aにランダムな整数データが代入されているものとする。 - 整数変数
gapを用意する。初期値はn/とする。2 - 次の手順を
gapの値が1になるまで繰り返す。- 次の操作を
gap回繰り返す。すなわち整数変数jは初期値0、終了値 gap-1でインクリメントする。a[j],a[j+gap],a[j+2gap], ……を基本挿入法でソートする。++j
gapを半分にする。
- 次の操作を
- 要素数
シンプルなことがよくわかります。このアルゴリズムを実装については演習の課題とします。
演習
演習1(難易度:easy)
ランダムな整数データを500個もつデータファイルを作成しましょう。データは最小値1、RandomData.に保存しましょう。このsketchのファイル名はGenerateRandomData.にしてください。
演習2(難易度:middle)
SelectionSort.のコードを参考に、frameRateを10に変更しましょう。ファイル名はShellSort.としてください。
演習3(難易度:middle)
基本交換法であるバブルソートのアルゴリズムを調べて、RandomData.をソートするsketchを作成しましょう。ファイル名はBubbleSort.としてください。
まとめ
- 専門家として知っておくべきアルゴリズムの例として、
ソートのアルゴリズムを学習しました。
学習の確認
それぞれの項目で、
- 基本選択法の仕組みが理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、
今ひとつスッキリしない。 - 理解できない。
- シェルソートの仕組みが理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、
今ひとつスッキリしない。 - 理解できない。
- バブルソートの仕組みが理解出来ましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、
今ひとつスッキリしない。 - 理解できない。
参考文献
- 『改訂C言語によるはじめてのアルゴリズム入門』
(河西朝雄 著、 技術評論社) - アルゴリズムの入門書。入門者に取っては十分に辞書的な内容である。丁寧に解説された良書。
演習解答
GenerateRandomData.pde - このコードで作成したデータファイル
RandomData.はスケッチフォルダtxt GenerateRandomData内にあります。他のsketchで利用する場合は、そのsketchのスケッチフォルダにコピーしてください。
- このコードで作成したデータファイル
ShellSort.pde BubbleSort.pde - 演習2と演習3のソートを実行した時、
描画された画面の美しさにはほれぼれすることでしょう。
- 演習2と演習3のソートを実行した時、
