===== 番兵法 =====
==== 線形探索 ====
線系探索を普通にやろうと思うと、だいたいこうなるよね?
〇 検索するデータ:Key
〇 データ列の数(配列数):N
〇 戻り値:
・データが見つかった時 :データの位置(index)
・データが見つからない時 :-1 (Not Foundの戻り値としてあり得ないindexを返す)
SequentialSearch()
・ i ← 0
■ i < N and A[i] != Key
| ・ i ← i + 1
■
▲ i => N
| ・ return -1
+---------------
| ・ return i
▼
Cで書いてみるとこんな感じ
#include
int main(void){
int n = 5; //配列数
int A[5] = {3, 1, 2, 5, 4}; //C言語ってconst int使えるんだっけ?
int i;
int Key = 8; //探索する数
printf("Key = %d\n", Key);
for (i = 0; i < n; i++) {
printf("%d\n", A[i]);
if (A[i] == Key) {
printf("見つかりました\n");
return 0;
}
}
printf("見つかりませんでした\n");
return 0;
}
ちなみに、疑似言語通りの動きをする関数を作るとこんな感じ(多分配列を関数に渡す云々とかやってないんだよね?)
#include
///
/// 大きさnの配列datの中からkeyのデータを探す関数
///
/// 配列のサイズ
/// 配列の名前
/// 探すデータ
///
/// 戻り値 i:Keyをdat[i]で見つけた。
/// -1:見つからなかった
///
int SequentialSearch(int n, int dat[], int key)
{
int i = 0;
while (i < n && dat[i] != key)
{
i = i + 1;
}
if (i >= n)
return -1;
else
return i;
}
int main()
{
int n = 10;
int A[10] = { 6,3,2,9,5,4,10,1,8,7 };
int Key = 8;
int res = SequentialSearch(n, A, Key);
if (res == -1)
printf("not found\n");
else
printf("Data is found in A[%02d] = %02d\n", res, A[res]);
}
はい。改良できるところどこよ?って思うかもしれないですが、ここです。\\
while (i < n && dat[i] != key)
(for文で書くとその改良が見えづらいですが)繰り返しの条件が、複合条件で「配列の境界チェック」AND「キーの発見チェック」になっています。\\
日本語で書くと、\\
**iでループを回すときに「配列が大きさnをオーバーしない、かつ、データの[i]は探しているキーではない」間ループを回す**\\
になっています。逆に言うとループを抜けるのは、「iが配列の大きさnを超えたとき」または、「キーが見つかった時」に配列の添え字を返す関数です。\\
それ以外はエラーとして―1を返します。\\
ここまでは、みんな大丈夫だと思います。\\
===== 番兵さん =====
この条件をちょい簡単にする方法を考えてみます。\\
やることは簡単で、「必ずどこかでKeyが見つかるようにしておく」です。今のやり方はKeyが見つからないときがあるので、配列よりも添え字がオーバーしちゃわないか\\
こわごわ確認しながらサーチしてます。\\
それを、配列の最大値(最大サーチするとこの次(N+1とする))= Keyにしておくと、
▲ A[i] == Key
| ・ res = i
▼
▲ i == N
| ・ A[0]~A[N-1]までにKeyはなかった(Nまでサーチしちゃってる)
+---------------
| ・ A[i]でKeyは見つかった (0~N-1のどこかでKeyを見つけてある)
▼
と書くことができます。つまり、上の疑似言語の「i < N and」がいらなくなるね!\\
このアルゴリズムを、普通の線系探索を参考に疑似言語としてまとめて書いてみます。\\
==== 番兵さん入り線形探索 ====
〇 検索するデータ:Key
〇 データ列の数(配列数):N+1
〇 戻り値:
・データが見つかった時 :データの位置(index)
・データが見つからない時 :-1 (Not Foundの戻り値としてあり得ないindexを返す)
SequentialSearch()
・ i ← 0
・ A[N] = Key
■ A[i] != Key
| ・ i ← i + 1
■
▲ i == N ?
| ・ return -1
+---------------
| ・ return i
▼
なんか妙にすっきりしたね笑\\
最後にソース追加しておくよ\\
#include
///
/// 大きさnの配列datの中からkeyのデータを探す関数
///
/// 配列のサイズ
/// 配列の名前
/// 探すデータ
///
/// 戻り値 i:Keyをdat[i]で見つけた。
/// -1:見つからなかった
///
int SequentialSearch(int n, int dat[], int key)
{
int i = 0;
while (i < n && dat[i] != key)
{
i = i + 1;
}
if (i >= n)
return -1;
else
return i;
}
///
/// 大きさnの配列datの中からkeyのデータを探す関数
///
/// 配列のサイズ
/// 配列の名前
/// 探すデータ
///
/// 戻り値 i:Keyをdat[i]で見つけた。
/// -1:見つからなかった
///
int SequentialSearchSentinel(int n, int dat[], int key)
{
dat[n] = key; //データの最後=配列数と同じインデックスのとこ
int i = 0;
while (dat[i] != key)
{
i = i + 1;
}
if (i == n + 1)
return -1;
else
return i;
}
int main()
{
int n = 10; //これはデータ数
//データ数+1の配列が必要
//一番後ろこの場合A[10]は、番兵さんが入るので空けとく
int A[11] = { 6,3,2,9,5,4,10,1,8,7 };
int Key = 8;
//int res = SequentialSearch(n, A, Key);
int res = SequentialSearchSentinel(n, A, Key);
if (res == n)
printf("not found\n");
else
printf("Data is found in A[%02d] = %02d\n", res, A[res]);
}