どうも!仙台ファクトリーのkouです。
探索アルゴリズムと格闘した報告をしたいと思います。
無知であることをお許しください。。。
問題文
以下のような1万個の数値(乱数)の配列があります。 1、3、6、14、34・・・・ 数値に規則性はなく、最大で100万あります。 ただ、昇順になっています。 上記に対して目的の数値の検索をする処理をチャートで表してください 目的の数値は100あり、その結果を以下のように出力します。 5は3番目 25はありませんでした 4000は4万番目
要件:出来るだけ処理時間を短縮したいです。
端的に言うと、 1万個の数値の中から目的となる100個の数値を素早く見つけるアルゴリズムを考えるというものだ。
問題文を見てふと思ったこと
- 与えられた1万個の乱数の配列が既に「昇順」に並んでいる→2分探索が使える
- 目的の数値も並び替えれば探索が早くなる?(漠然と)
2分探索については、前回の課題であるアルゴリズムとフローチャートについての調査でざっとやっただけでロジックの理解は曖昧な状態である。このロジックを考えることが今回の課題を解決する鍵になりそうだ。
早速問題に取り掛かるが…
*これ以降は、問題文の1万個の数値を『探索元データ』、100件の目的数値を『目的データ』と表記する。
最初に考えたロジックが次の通りだ。(2分探索まがいのことをやっているつもり…)
用意
探索元データの配列 array_m[10000]
目的データの配列 array_n[100]
探索元データの中央要素の添え字をmid
探索元データの軸をjiku
とする。
*お気づきかもしれないが、jikuという意味不明な変数を用意してしまったのが、どハマリした原因である。
方針
- 探索元データの中央要素と目的データを比較
データが一致したなら探索終了。不一致なら探索継続。 ここでは、if(array_m[mid] == array[0])、if(array_m[mid] > array[0])、if(array_m[mid] < array_[0])といった単純な比較を行っている。 2分探索に理解のある人はここまでなら理解できるはず。2分探索は基本的にはこの繰り返しである。 つまり、midの値を分岐に合わせて調整して比較していくということである。midが軸なのである。
しかし、私はここで魔法の変数jikuを用意してしまった。 これ以上、文章で解説するとややこしくなるのでコードで構造を示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
最初はmidを使い比較して2回目以降、midの値をjikuに移し比較している。 if文の中の処理は省略しているが、ざっくり解説すると
- midの値を半分にする
- midの値をjikuに足し引きしている
ということを行っている。 目的データとjikuを添え字とする探索元データの配列要素と比較を行い、目的データの値が大きい場合は、midの値をjikuに加算し、小さい場合は、midの値をjikuに減算している。
問題点
- 探索元データが存在するのに探索を終了する場合がある
探索元データの要素数を1万とした場合、midの値は5000,2500,1250,625,,,,,,,19,9,4,2,1と 半分になっていく。しかしこの場合、終盤の細かい部分の探索が粗くなってしまう
以下に出力結果の一例を示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
このように範囲を絞りきる前に、midの値が0になってしまうことがあった。
そしてここで暫く行き詰ってしまった。。。
結局、解決策が浮かばなかった件
あと一歩のところで解決できそうな気がするのだが、これ以降前に進まなかった。
そしてあれこれ考えている内にあることに気づいてしまったのである。
続きは
課題報告 探索アルゴリズム【成功編】で!