Where can I get a "useful" C++ binary search algorithm?

C++AlgorithmStlBinary Search

C++ Problem Overview


I need a binary search algorithm that is compatible with the C++ STL containers, something like std::binary_search in the standard library's <algorithm> header, but I need it to return the iterator that points at the result, not a simple boolean telling me if the element exists.

(On a side note, what the hell was the standard committee thinking when they defined the API for binary_search?!)

My main concern here is that I need the speed of a binary search, so although I can find the data with other algorithms, as mentioned below, I want to take advantage of the fact that my data is sorted to get the benefits of a binary search, not a linear search.

so far lower_bound and upper_bound fail if the datum is missing:

//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

Note: I'm also fine using an algorithm that doesn't belong to the std namespace as long as its compatible with containers. Like, say, boost::binary_search.

C++ Solutions


Solution 1 - C++

There is no such functions, but you can write a simple one using std::lower_bound, std::upper_bound or std::equal_range.

A simple implementation could be

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
}

Another solution would be to use a std::set, which guarantees the ordering of the elements and provides a method iterator find(T key) that returns an iterator to the given item. However, your requirements might not be compatible with the use of a set (for example if you need to store the same element multiple times).

Solution 2 - C++

You should have a look at std::equal_range. It will return a pair of iterators to the range of all results.

Solution 3 - C++

There is a set of them:

http://www.sgi.com/tech/stl/table_of_contents.html

Search for:

On a separate note:

They were probably thinking that searching containers could term up more than one result. But on the odd occasion where you just need to test for existence an optimized version would also be nice.

Solution 4 - C++

If std::lower_bound is too low-level for your liking, you might want to check boost::container::flat_multiset. It is a drop-in replacement for std::multiset implemented as a sorted vector using binary search.

Solution 5 - C++

The shortest implementation, wondering why it's not included in the standard library:

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;
}

From https://en.cppreference.com/w/cpp/algorithm/lower_bound

Solution 6 - C++

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;
}

Example: Consider an array, A=[1,2,3,4,5,6,7,8,9] Suppose you want to search the index of 3 Initially, start=0 and end=9-1=8 Now, since start<=end; mid=4; (array[mid] which is 5) !=3 Now, 3 lies to the left of mid as its smaller than 5. Therefore, we only search the left part of the array Hence, now start=0 and end=3; mid=2.Since array[mid]==3, hence we got the number we were searching for. Hence, we return its index which is equal to mid.

Solution 7 - C++

Check this function, qBinaryFind:

> RandomAccessIterator qBinaryFind ( RandomAccessIterator begin, RandomAccessIterator end, const T & value ) > > Performs a binary search of the range > [begin, end) and returns the position > of an occurrence of value. If there > are no occurrences of value, returns > end. > > The items in the range [begin, end) > must be sorted in ascending order; see > qSort(). > > If there are many occurrences of the > same value, any one of them could be > returned. Use qLowerBound() or > qUpperBound() if you need finer > control. > > Example: > >
> > QVector vect; > vect << 3 << 3 << 6 << 6 << 6 << 8; >
> QVector::iterator i = > qBinaryFind(vect.begin(), vect.end(), 6); > // i == vect.begin() + 2 (or 3 or 4)

The function is included in the <QtAlgorithms> header which is a part of the Qt library.

Solution 8 - C++

std::lower_bound() :)

Solution 9 - C++

A solution returning the position inside the range could be like this, using only operations on iterators (it should work even if iterator does not arithmetic):

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-p)/2;  // overflow safe (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;

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRobert GouldView Question on Stackoverflow
Solution 1 - C++Luc TourailleView Answer on Stackoverflow
Solution 2 - C++Luc HermitteView Answer on Stackoverflow
Solution 3 - C++Martin YorkView Answer on Stackoverflow
Solution 4 - C++ZunTzuView Answer on Stackoverflow
Solution 5 - C++trozenView Answer on Stackoverflow
Solution 6 - C++Siddharth Kumar ShuklaView Answer on Stackoverflow
Solution 7 - C++LawandView Answer on Stackoverflow
Solution 8 - C++moogsView Answer on Stackoverflow
Solution 9 - C++Michele BelottiView Answer on Stackoverflow