views:

1179

answers:

5

I need a binary search algorithm that is compatible with the C++ standard containers, something like std::binary_search in the standard library's <algorithm> header, but unlike std::binary_search, 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!!!)

Edit: 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 that my data is already sorted to get the benefits of a binary search, not just any search.

so far lower_bound and upper_bound fail, because 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

Also I really doubt lower_bound and upper_bound are implemented as binary_searches, because they work just as well with unsorted data, and there is no way to provide that information through arguments or policies. Ok as first mentioned by vividos, they DO require sorted data, which means they ARE binary searches, so the world is good again :)

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

+4  A: 

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

Luc Hermitte
fixed range_equal -> equal_range
Robert Gould
Indeed. My mistake.
Luc Hermitte
+4  A: 

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.

Martin York
binary_search doesn't return an iterator as I mentioned earlier, that's why I'm looking for an alternative.
Robert Gould
Yes, I know. But it fits in the set of binary search algorithms. So its nice for others to know about.
Martin York
binary_search is just, like so many other things in the STL, named wrong. I hate that. Testing for existence is not the same as searching for something.
OregonGhost
my main issue with the above algorithms is they depend on a "naive" implementation, in the sense that they do not make use of the situation's context, in this case sorted data. And as OregonGhost mentions, std::binary_search doesn't do what its advertising :)
Robert Gould
missed the sorted part in the documentation, so you can forget about what I just said
Robert Gould
+1  A: 

std::lower_bound() :)

moogs
+12  A: 

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 && *i == val)
        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).

Luc Touraille
yes this works, and I have a similar implementation right now, however it's a "naive" implementation, in the sense that it's not making use of the situation's context, in this case sorted data.
Robert Gould
I don't really understand your comment, since lower_bound can only be used on sorted data. Complexity is lower than using find (see edit).
Luc Touraille
sorry I forgot they had to be sorted, so your implementation is correct, and it is taking advantage of the sorted data!
Robert Gould
+2  A: 

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

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

Lawand