二分探索で配列の最後の要素を見つける方法
-
20-09-2019 - |
質問
二分探索アルゴリズムでは、上限要素は次のとおりです。 array.length-1
, では、配列の最後の要素を見つけるにはどうすればよいでしょうか?
長さ 8 の配列の要素の下限と上限がそれぞれ 6 と 7 の場合、中間要素は次のようになります。
mid=(6+7)/2 つまりジャワでは6
解決
これは本当にダウン右正しく選択中間点で比較を使用することになります。 (可変型宣言せず)、例えば、
binsearch(a,val,left,right){
if(left==right) return left;
mid = (left+right)/2;
if(a[mid] < val)
return binsearch(a,val,mid+1,right);
else
return binsearch(a,val,left,mid);
}
あなたは(それが配列の右端の要素であっても)のvalに一致する一番左の要素のインデックスを提供します。あなたは明示的に最後の二つをチェックしたり、整数切り捨てに建て使用するのではなく、切り上げする必要はありません。
あなたがvalのに等しい右端の要素のインデックスをしたい場合は、しかし、その後は、
により与えられるべきであるとミッド<にオペレータ>に変更する必要がありますmid = (left+right+1)/2;
それはそれと同じくらい簡単です。
編集:もう一つ、私はこのために使用私のコードを見て、あなたはまた、右端の要素で終わるためにbinsearchへの呼び出しを変更する必要があることに気づきました。私はちょうど(私が最初の場所で行われているはずです)、このための完全なコードを投稿します。ここでのvalに等しい右端の要素を見つけるためのバイナリサーチだ。
binsearch(a,val,left,right){
if(left==right) return left;
mid = (left+right+1)/2;
if(a[mid] > val)
return binsearch(a,val,left,mid-1);
else
return binsearch(a,val,mid,right);
}
他のヒント
最も簡単な方法は、半開きの範囲を使用することです。この方法では、直接最初の項目にご下限ポイントものの、アレイ内の1つのステップの最後の有効な項目の後にあなたの上限ポイント。ただし、検索時に、あなたは包括的なとして、あなたの範囲を扱う - 範囲外の上限は、有効な結果を「一致が見つからない」です。
。あなたが持っている各反復の開始時...
lower <= target <= upper
「ターゲット」が見つかり、返されるインデックスを意味します。
あなたは "(+上下)/ 2" として半ばを計算します。これは切り捨てているので、半ばは重要である、上側のと同じになることはありません。 「上」ので外の境界が、我々は合法的に評価することはできません「配列[上位]」であってもよい。
の最初のアイテムを検索するにより-大きいか、等しい鍵...
if array[mid] >= k : lower <= target <= mid
if array[mid] < k : mid+1 <= target <= upper
大なりキーの最初の項目を検索するには...
if array[mid] > k : lower <= target <= mid
if array[mid] <= k : mid+1 <= target <= upper
これらの部分範囲は包括的、かつ正確に会うが、重複してはいけません。我々一のサブレンジのための中間+ 1を使用する理由の一部である中間に単一アイテムの重複(簡単に間違い)、無限ループで結果、
2回の検索の間に変化する全ての比較演算子であることに注意してください。
最後少ない又は等しく見つけるために、最初に大きい見つけ、その結果から1を引きます。あなたが得ることができます-1、アレイ内のすべての項目がキーより大きい場合ます。
注 - あなたは各反復におけるミッドに対してのみテストキー(あなたは、上限と下限が既に正しいことを知っている)、あなたが唯一の条件テストを行います。
。(それはあなたが必要なものの場合)範囲外のチェックと平等のチェックを行います。のの外側のループのます。
int find_first_ge (int key)
{
int lower = 0;
int upper = array.length;
while (upper > lower)
{
int mid = (lower + upper) / 2;
if (array [mid] >= key) // for find_first_gt, use ">" here
{
upper = mid;
}
else
{
lower = mid + 1;
}
}
return lower;
}
注
これを修正することを意図したものと同じように無限ループの多いこれを左にいくつかのミスを修正するために編集されます。
トリックは、元の完全な範囲よりも少なくとも一つの小さな各キーの試験の後、必要に応じて二分サブレンジが正確であることを確認し、の常にのことです - と過信と悪いメモリを介し、それは正確に何私は間違って得ることができました。それは間違っている場合、私はの大きなの問題持っているので、上記の、使用頻度の高いライブラリー(マルチウェイツリーライブラリ内のノード内の検索)で、実際の作業コードに基づいている; - )
注
文言を改善し(範囲は半分開いているが、それらは包括として扱われることに注意)サブレンジ境界の説明を簡単にするために再編集。
あなたの下限とあなたの上限が互いの1の範囲内にある場合は、両方をチェックします。
あなたは、それぞれの時間を切り上げる可能性があります。
(6 + 7)/2.0 == 6.5
切り上げて、あなたは7を思い付くでしょう。
それとも、単にあなたの中間点に1を追加することができます。
半ば=(6 + 7)/ 2 + 1
もう一つの方法は、以下の再帰のために+1または-1にあなたの開始や終了点を変更しています。これは、対象のWikipediaの記事は、いくつかの実装で示したものです。
分=ミッド+ 1
または
最大=半ば1
二分探索は、正確に正しく検索するのが難しいことで知られています。さまざまな問題と特殊なケースに関する非常に徹底的な分析が、正しい実装とともに行われています。 プログラミングパール, プログラマーなら誰もが一度は読んだことがあるであろう本。