random select algorithm(選択アルゴリズム)
2376 ワード
≪アルゴリズムの選択|Select Algorithm|oem_src≫:ソートされていないシーケンスでK番目に小さい要素を選択します.
pseudo codeで書き終わると、5分もかかりませんでしたが、実際にコードデバッグに変換するのに30分以上かかりました.以下はいくつかの原因です.
1.普段pseudo codeを書くときは、人間との正常な思考がずっと続き、配列は1から始まり、最小のk番目の要素は最小のk番目の要素である.実際にコードを書くのは、配列時に0から始まります.この点は、混同しやすい.私の感覚は、pseudo codeとプログラムコードの約束が一致するように、自分の記号とルールを定義することです.例えば、ランキングは0から始めて、0が小さくて、1が小さくて、..k番目は小さいです.例えば、集合統一は半開半閉の表現方法を採用し、配列に関する呼び出しの伝達パラメータ(begin,end)はすべて半開半閉である.A[begin:end)
2.divide-and-conque法で問題を解決する場合、境界条件が間違えやすい.境界条件を書くときは、簡単な例で正しいかどうかを見たほうがいいと思います.さもないと、プログラムが走って、崩壊したら、悲劇になります.
3.関数の定義は明確にし、その意味は必ず明確にしなければならない.入力されたパラメータの意味、返された値の意味.私が今回バグを作ったのはrandomのせいだselect関数が最初に定義した値の意味は明確ではありません.
刀を研いで柴刈りを間違えず、定義を明確にしてから手を出す.
static int random_select(int begin, int end, int k)
{
assert(begin < end);
assert(k >= 0);
assert(k < end-begin);
int rand = randint(begin, end);
int left, right;
partition(begin, end, rand, &left, &right);
int idx = k+begin;
if (idx < left)
return random_select(begin, left, k);
else if (idx >=left && idx<=right)
return idx;
else
return random_select(right+1, end, idx-right-1);
}
static void partition(int begin, int end, int pivot_index, int *ret_left, int *ret_right)
{
#if 0
printf("***********in partition*****************
");
print_array(begin, end);
printf("pivot_index = %d
", pivot_index);
#endif
int pivot = A[pivot_index];
swap(begin, pivot_index);
int left = begin;
int right = begin;
int i;
for (i=begin+1; i<end; i++)
{
if (A[i] > pivot)
;
else if (A[i] == pivot)
{
swap(right+1, i);
right += 1;
}
else
{
swap(left, i); left += 1;
swap(right+1, i); right += 1;
}
}
*ret_left = left;
*ret_right = right;
#if 0
print_array(begin, end);
printf("left = %d, right = %d
", left, right);
printf("***********end partition*****************
");
#endif
}
pseudo codeで書き終わると、5分もかかりませんでしたが、実際にコードデバッグに変換するのに30分以上かかりました.以下はいくつかの原因です.
1.普段pseudo codeを書くときは、人間との正常な思考がずっと続き、配列は1から始まり、最小のk番目の要素は最小のk番目の要素である.実際にコードを書くのは、配列時に0から始まります.この点は、混同しやすい.私の感覚は、pseudo codeとプログラムコードの約束が一致するように、自分の記号とルールを定義することです.例えば、ランキングは0から始めて、0が小さくて、1が小さくて、..k番目は小さいです.例えば、集合統一は半開半閉の表現方法を採用し、配列に関する呼び出しの伝達パラメータ(begin,end)はすべて半開半閉である.A[begin:end)
2.divide-and-conque法で問題を解決する場合、境界条件が間違えやすい.境界条件を書くときは、簡単な例で正しいかどうかを見たほうがいいと思います.さもないと、プログラムが走って、崩壊したら、悲劇になります.
3.関数の定義は明確にし、その意味は必ず明確にしなければならない.入力されたパラメータの意味、返された値の意味.私が今回バグを作ったのはrandomのせいだselect関数が最初に定義した値の意味は明確ではありません.
刀を研いで柴刈りを間違えず、定義を明確にしてから手を出す.