導入
第9回より
- 配列とコレクション
- ソート
- サーチ
- 再帰
今回はその第3回目として
展開
サーチとは
サーチ
サーチのアルゴリズムには、
サーチは大変広い成果のある項目で、
代表的なサーチアルゴリズム
サーチを行うアルゴリズムの例として次のものが挙げられます。
- 線形探索法
- 二分探索法
- ハッシュテーブルを利用した探索法
線形探索法
線形探索という言葉は英語のLinear Searchの直訳です。データの集合を先頭要素から、
線形探索の計算量はO(n)です。データの要素数に比例して増加します。何と言ってもコードがシンプルですから要素数が少なければ活用したいアルゴリズムです。ソートされていないデータの集合に対しても使用できるメリットがあります。
その昔、
線形探索のアルゴリズムを実装したsketchは次のとおりです。
LinearSearch.pde
// 線形探索 Linear Search
// 番兵無し No Sentinel
final int NUMBER_OF_RANDOM_DATA = 500;
final String DATA_FILE_NAME = "RandomData.txt";
final int DIAMITER = 5;
final int SEARCHING_VALUE = 37;
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(60);
stroke(255,0,0);
}
void loadData(){
String lines[] = loadStrings(DATA_FILE_NAME);
for(String val : lines){
nums.add(int(val));
}
}
void linearSearch(){
if (SEARCHING_VALUE == nums.get(i)) {
println("Hit!");
ellipse(i,nums.get(i),DIAMITER*2,DIAMITER*2);
exit();
}
}
void draw(){
println("Searching value is " + SEARCHING_VALUE);
if (i < NUMBER_OF_RANDOM_DATA){
//サーチ1パス
linearSearch();
//結果をプロット
println("Count " + i);
clear();
for (int k=0; k < nums.size(); k++) {
if ( k == i ) {
ellipse(k,nums.get(k),DIAMITER*2,DIAMITER*2);
} else {
ellipse(k,nums.get(k),DIAMITER,DIAMITER);
}
}
++i;
}
}
二分探索法
二分探索法は別名バイナリサーチ
- 二分探索法のアルゴリズム
- データはn個の整数、
ソート済みで配列dataに格納されているとします。 - 探索する値を格納する整数変数をaとします。
- 探索範囲を表す整数変数lowとupperを用意します。
- 初期値はlow=0, upper=n-1とします。
- 探索位置を表す整数変数xは初期値(low+upper)/2とします。
- 次の手順を行います。
- data(x)とaを比較します。
- 双方が等しければ探索終了です。
- a<data(x)ならば、
upper=x-1とします。data(x)<aならばlow=x+1とします。x=(low+upper)/2とします。upper<lowとなったら探索終了です。 - 1へ戻ります。
- データはn個の整数、
このアルゴリズムを実装するのを今回の演習とします。ソート済みのデータを作成して、
二分探索法の計算量
データがn個のときの二分探索法は、
そのため、
ハッシュテーブルを用いたサーチ
ハッシュテーブルを用いたサーチでは、
例えば、
計算量はハッシュ関数の計算を実行の1単位ととらえるならばO(1)です。そのため高速に目的のデータを取得できます
なお、
簡単なハッシュ関数を実装したsketchは次のとおりです。ある値Aをハッシュ関数で計算した値を添字として、
HashSearch.pde
int SEED = 193; // 適当な素数
int DATA_NUM = 2017; // テーブルの大きさ
String table[] = new String[DATA_NUM];
String VAL1 = "ABCDE";
String VAL2 = "FGHIJ";
String VAL3 = "HOGE";
void setup(){
println("hash(" + VAL1 + ") = " + hash(VAL1) + " is Stored."); table[hash(VAL1)] = VAL1;
println("hash(" + VAL2 + ") = " + hash(VAL2) + " is Stored."); table[hash(VAL2)] = VAL2;
println("get " + VAL2 + " from table[" + hash(VAL2) + "], it's " + table[hash(VAL2)]);
println("get " + VAL3 + " from table[" + hash(VAL3) + "], it's " + table[hash(VAL3)]);
}
int hash(String s){
long h = 0;
char[] c = s.toCharArray();
for(char val: c){
h = h * SEED + Character.getNumericValue(val);
}
int index = (int)(h % DATA_NUM);
return index;
}
作業 sketchHashSearch.
で、
演習
演習1(難易度:easy)
連載第10回で作成したsketchを活用して、SortedData.
としてください。
演習2(難易度:middle)
本文に掲載したアルゴリズムと、SortedData.
を使用しましょう。このsketchのファイル名はBinarySearch.
にしてください。
まとめ
- サーチとその代表的なアルゴリズムを学習しました。
- 各アルゴリズムの計算量を求め、
比較しました。
学習の確認
それぞれの項目で、
- 線形探索法の仕組みが理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、
今ひとつスッキリしない。 - 理解できない。
- 二分探索法の仕組みが理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、
今ひとつスッキリしない。 - 理解できない。
- ハッシュテーブルを用いた探索の仕組みが理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、
今ひとつスッキリしない。 - 理解できない。
- 計算量の求め方が理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、
今ひとつスッキリしない。 - 理解できない。
参考文献
- 『改訂C言語によるはじめてのアルゴリズム入門』
(河西朝雄 著、 技術評論社) - アルゴリズムの入門書。入門者に取っては十分に辞書的な内容である。丁寧に解説された良書。
『はじめMath! Javaでコンピュータ数学 第75回 計算量の数学 計算量と実際のコード その1』 - コンピュータ数学を高校生程度の学力で分かるように解説したWeb連載です。計算量の解説の際、
バイナリサーチをとりあげました。参考にしてみてください。
- コンピュータ数学を高校生程度の学力で分かるように解説したWeb連載です。計算量の解説の際、
演習解答
BubbleSortAndSaveData.
pde - バブルソートを使用してデータをソートし保存してみました。スケッチフォルダに
RandomData.
をコピーして用意してから実行しましょう。txt
- バブルソートを使用してデータをソートし保存してみました。スケッチフォルダに
BinarySearch.
pde