Reputation: 174
Recently, while working on a programming problem in C++, I came across something interesting. My algorithm used a really large set and would use std::lower_bound on it a great deal of times. However, after submitting my solution, contrary to the math I did on paper to prove that my code was fast enough, it ended up being far too slow. The code looked something like this:
using namespace std;
set<int> s;
int x;
//code code code
set<int>::iterator it = lower_bound(s.begin(),s.end(),x);
However, after getting a hint from a buddy to use set::lower_bound, the algorithm in question worked waaaaaaaay faster than before, and it followed my math. The binary search after changing:
set<int>::iterator it = s.lower_bound(x);
My question is what's the difference between these two? Why does one work much, much faster than the other? Isn't lower_bound supposed to be a binary search function that has the complexity O(log2(n))? In my code it ended up being way slower than that.
Upvotes: 15
Views: 3088
Reputation: 36832
std::set
is typically implemented as a self-balancing tree with some list-like structure tied into it. Knowing this structure, std::set::lower_bound
will traverse the tree knowing the properties of the tree structure. Each step in this just means following a left or right child branch.
std::lower_bound
needs to run something akin to a binary search over the data. However since std::set::iterator
is bidirectional (not random access), this is much slower, a lot of increments need to be done between the checked elements. The work done between elements is thus much more intense. In this case the algorithm will check the element half way between A and B, then adjust one of A or B, find the element half way between them, and repeat.
Upvotes: 11
Reputation: 4094
After reading the API of std::lower_bound
On non-random-access iterators, the iterator advances produce themselves an additional linear complexity in N on average.
And I think STL set is using non-random-access iterators, so it is not doing a O(log N) binary search if using on STL set
Upvotes: 3
Reputation: 16086
std::lower_bound
always guarantees a O(log n)
comparisons, only guarantees O(log n)
time if passed a RandomAccessIterator
, not just a ForwardIterator
which does not provide constant-time std::advance
.
The std::set::lower_bound
implementation of the same algorithm is able to use internal details of the structure to avoid this problem.
Upvotes: 1
Reputation: 8805
std::lower_bound
is a generic binary search algorithm, meant to work with most STL containers. set::lower_bound
is designed to work with std::set
so it takes advantages of the unique properties of std::set
.
As std::set
is often implemented as a red-black tree, one can imagine std::lower_bound
iterating across all nodes, while set::lower_bound
just traverses down the tree.
Upvotes: 1