2017年11月28日
《その155》 「 2分探索関数 」 の改良
「 2分探索関数 」 の改良
新版明解C++中級編 p.124 にある改良版2分探索関数 binsearchx のコードは、少し誤植があり、そのままではうまく動作しないので、修正した binsearchx関数と、それを利用するプログラムを以下に書きました。
// ------------------------------------
#include <string>
#include <iostream>
void* binsearchx(
const void* key, // キー値へのポインタ
const void* base, // 配列へのポインタ
size_t nmemb, // 要素の個数
size_t size, // 要素1つ分の大きさ
int(*compar)(const void*, const void*)) {
if (nmemb > 0) {
// 検索対象の配列の先頭要素へのポインタ
// の値を const char*型の x に代入
const char* x
= reinterpret_cast<const char*>(base);
// 最初の検索左端は base[0]
size_t pl = 0;
// 最初の検索右端は base[nmemb - 1]
size_t pr = nmemb - 1;
// 比較関数は、&x[pc * size]
// すなわち &base[pc] の指す base[pc]
// の値とkeyの指す値とを比較すること
// になります。
size_t pc;
while (1) {
// pc の値を決めます。
pc = (pl + pr) / 2;
// ポインタ key と
// ポインタ &x[pc * size] を
// 比較関数に渡して、
// 調査結果を int型の comp
// で受け取ります。
// ポインタ &x[pc * size] は
// ポインタ &base[pc] と同じ
// アドレスなので、
// 比較関数内で keyの指す値
// と base[pc] の値とを比較
// でます。
int comp = compar(
key,
reinterpret_cast<const void*>
(&x[pc * size])
);
// comp == 0 は検索成功。
if (comp == 0) {
// base[pc] が keyの指す値と一致
// することが分かりましたが、
// もっと先頭寄りに同じ値が
// あるかも知れないので、
// 添字の値をデクリメントし
// ながら調べてみます。
for (; pc > pl; pc--) {
if (compar(
key,
reinterpret_cast<const void*>
(&x[(pc - 1) * size])
)
)
// compar関数から、0 以外
// の値が返ってきたの
// で、base[pc]より前
// にはもう同じ値は
// ないことが判明。
// よって、この時点で
// break;
break;
}
// ポインタ &x[pc * size]すなわち
// base[pc] を指すポインタ
// を void型にキャストして
// 返却します。
return const_cast<void*>(
reinterpret_cast<const void*>
(&x[pc * size])
);
}
// 探索範囲の先頭と末尾が一致したら、
// 見つからなかったということなの
// で break; し、
// 関数の末尾に飛んで、
// return NULL;
else if (pl == pr)
break;
// comp > 0 ということは、
// keyの指す値 > base[pc]
// よって、探索範囲を後半に
// 絞り込みます。
else if (comp > 0)
pl = pc + 1;
// この行まで来たということは、
// comp < 0
// つまり、
// keyの指す値 < base[pc]
// よって、探索範囲を前半に絞り
// 込みます。
else if (pc > 0)
pr = pc - 1;
// この行まで来たということは、
// comp < 0 && pc == 0
// これ以上、探索範囲を前方にで
// きないので、
// break; し、
// 関数の末尾まで進んで、
// return NULL;
else
break;
}
}
return NULL;
}
int acmp(char* x, char* y) { // 比較関数
return strcmp(x, y);
}
int pcmp(char* x, char** y) { // 比較関数
return strcmp(x, *y);
}
int ncmp(int* x, int* y) { // 比較関数
return *x < *y ? -1 : *x > *y ? 1 : 0;
}
void existence(int n) {
std::cout << n << "番目\n";
}
void non_existence() {
std::cout << "該当なし\n";
}
int main() {
char a[][5]
= { "aaa", "ab", "bab", "bab",
"bab", "bab", "bbba" };
const char* p[]
= { "aaa", "ab", "bab", "bab",
"bab", "bab", "bbba" };
int num[]
= { 11, 25, 25, 25, 25, 25,
25, 57, 65, 77, 80 };
// ------------------------------------
std::cout << "◆";
for (int i = 0; i < 7; i++)
std::cout << a[i] << ' ';
std::cout << '\n';
char key1[10];
std::cout << " 探索する文字列 : ";
std::cin >> key1;
std::cout << " " << key1 << " → ";
void* f = binsearchx(
key1,
a,
sizeof(a) / sizeof(a[0]),
sizeof(a[0]),
reinterpret_cast<int(*)(
const void*,
const void*)
> (acmp)
);
if (f == 0) non_existence();
else existence((char(*)[5])f - a + 1);
// ------------------------------------
std::cout << "\n◆";
for (int i = 0; i < 7; i++)
std::cout << p[i] << ' ';
std::cout << '\n';
char key2[10];
std::cout << " 探索する文字列 : ";
std::cin >> key2;
std::cout << " " << key2 << " → ";
f = binsearchx(
key2,
p,
sizeof(p) / sizeof(p[0]),
sizeof(p[0]),
reinterpret_cast<int(*)(
const void*,
const void*)
>(pcmp)
);
if (f == 0) non_existence();
else existence((char**)f - p + 1);
// ------------------------------------
std::cout << "\n◆";
for (int i = 0; i < 11; i++)
std::cout << num[i] << ' ';
std::cout << '\n';
int key;
std::cout << " 探索する整数値 : ";
std::cin >> key;
std::cout << " " << key << " → ";
f = binsearchx(
&key,
num,
sizeof(num) / sizeof(num[0]),
sizeof(num[0]),
reinterpret_cast<int(*)(
const void*,
const void*)
>(ncmp));
if (f == 0) non_existence();
else existence((int*)f - num + 1);
}
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/7016009
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック