C++ STLコンテナと互換性のあるバイナリ検索アルゴリズム、std::binary_search
標準ライブラリの<algorithm>
ヘッダーですが、要素が存在するかどうかを示す単純なブール値ではなく、結果を指すイテレーターを返す必要があります。
(補足として、binary_searchのAPIを定義したとき、標準委員会は一体何を考えていましたか?!)
ここでの主な懸念は、バイナリ検索の速度が必要なことです。したがって、以下で説明するように、他のアルゴリズムでデータを見つけることができますが、バイナリの利点を得るためにデータがソートされるという事実を利用したいです線形検索ではなく検索。
これまでのところ lower_bound
およびupper_bound
データムがない場合は失敗します。
//lousy pseudo code
vector(1,2,3,4,6,7,8,9,0) //notice no 5
iter = lower_bound_or_upper_bound(start,end,5)
iter != 5 && iter !=end //not returning end as usual, instead it'll return 4 or 6
注:コンテナと互換性がある限り、std名前空間に属さないアルゴリズムを使用しても問題ありません。たとえば、boost::binary_search
。
そのような関数はありませんが、 std::lower_bound
、 std::upper_bound
、または std::equal_range
を使用して簡単な関数を作成できます。 。
簡単な実装は
template<class Iter, class T>
Iter binary_find(Iter begin, Iter end, T val)
{
// Finds the lower bound in at most log(last - first) + 1 comparisons
Iter i = std::lower_bound(begin, end, val);
if (i != end && !(val < *i))
return i; // found
else
return end; // not found
}
別の解決策は、std::set
を使用することです。これは、要素の順序を保証し、指定されたアイテムに反復子を返すiterator find(T key)
メソッドを提供します。ただし、要件はセットの使用と互換性がない場合があります(たとえば、同じ要素を複数回保存する必要がある場合)。
std::equal_range
。すべての結果の範囲へのイテレーターのペアを返します。
それらのセットがあります:
http://www.sgi.com/tech/stl/table_of_contents.html
検索する:
別のメモ:
彼らはおそらく、コンテナを検索すると複数の結果が得られると考えていたでしょう。ただし、存在をテストするだけの場合は、最適化されたバージョンもいいでしょう。
Std :: lower_boundが低すぎる場合は、 boost :: container :: flat_multiset を確認することをお勧めします。これは、バイナリ検索を使用してソートされたベクトルとして実装されたstd :: multisetのドロップイン置換です。
最も短い実装で、なぜ標準ライブラリに含まれていないのか疑問に思います:
template<class ForwardIt, class T, class Compare=std::less<>>
ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={})
{
// Note: BOTH type T and the type after ForwardIt is dereferenced
// must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
// This is stricter than lower_bound requirement (see above)
first = std::lower_bound(first, last, value, comp);
return first != last && !comp(value, *first) ? first : last;
}
std :: lower_bound():)
この関数を確認してください qBinaryFind :
RandomAccessIterator qBinaryFind ( RandomAccessIterator begin, RandomAccessIterator end, const T & value )
範囲[begin、end)のバイナリ検索を実行し、valueの出現位置を返します。値の出現がない場合、endを返します。
[begin、end)の範囲のアイテムは、昇順でソートする必要があります。 qSort()を参照してください。
同じ値のオカレンスが多数ある場合、いずれかが返される可能性があります。より細かい制御が必要な場合は、qLowerBound()またはqUpperBound()を使用します。
例:
QVector<int> vect; vect << 3 << 3 << 6 << 6 << 6 << 8; QVector<int>::iterator i = qBinaryFind(vect.begin(), vect.end(), 6); // i == vect.begin() + 2 (or 3 or 4)
この関数は、 Qt ライブラリの一部である<QtAlgorithms>
ヘッダーに含まれています。
int BinarySearch(vector<int> array,int var)
{
//array should be sorted in ascending order in this case
int start=0;
int end=array.size()-1;
while(start<=end){
int mid=(start+end)/2;
if(array[mid]==var){
return mid;
}
else if(var<array[mid]){
end=mid-1;
}
else{
start=mid+1;
}
}
return 0;
}
例:配列A = [1,2,3,4,5,6,7,8,9]を考えます。最初に3のインデックスを検索するとします。最初はstart = 0、end = 9-1 = 8です、start <= end; mid = 4; (array [mid] is 5)!= 3ここで、3はmidの左に5よりも小さいため、配列の左部分のみを検索します。したがって、start = 0とend = 3になります。 mid = 2.array [mid] == 3であるため、検索対象の数字が得られました。したがって、midに等しいインデックスを返します。
範囲内の位置を返すソリューションは、イテレーターでの操作のみを使用して、次のようになります(イテレーターが算術演算を行わなくても機能するはずです):
template <class InputIterator, typename T>
size_t BinarySearchPos(InputIterator first, InputIterator last, const T& val)
{
const InputIterator beginIt = first;
InputIterator element = first;
size_t p = 0;
size_t shift = 0;
while((first <= last))
{
p = std::distance(beginIt, first);
size_t u = std::distance(beginIt, last);
size_t m = (p+u)/2;
std::advance(element, m - shift);
shift = m;
if(*element == val)
return m; // value found at position m
if(val > *element)
first = element++;
else
last = element--;
}
// if you are here the value is not present in the list,
// however if there are the value should be at position u
// (here p==u)
return p;
}