I never remember what precisely lower_bound returns, so this is me collecting this information
in a way that makes sense to me. The API docs say
Returns an iterator pointing to the first element in the range
[first,last)which does not compare less than val.
- So
lower_bound(first, last, bound)it finds the leftmost locationlin[first..last)such thatas[l] >= bound. - See that it can be equal to the value
bound.
In contrast, upper_bound says:
Returns an iterator pointing to the first element in the range
[first,last)which compares greater than val.
- So
upper_bound(first, last, bound)it finds the leftmost locationlin[first..last)such thatas[l] > bound.
§ Pictorially
If we have a range:
<<<<<<< ======= >>>>>>>><<<<<<< ======= > | |<<<<<<< ======= > L R- The
<values are less than bound,=values are equal to bound, and>values are greater than bound, thenlower_boundandupper_boundreturn iterators to represent the=range[L, R]in half-open form. - So we will have
[lower_bound, upper_bound) = [L, R]. This matches the C++ API where everything uses half-open intervals.
<<<<<<< ======= >>>>>>>><<<<<<< ======= > L R |<<<<<<< ======= > lower upper§ Traversals
- : loop as
for(auto it = lowerbound(l); it < upperbound(h); ++it) {}. This works sinceupperbound(h)will find first index> h, so we include all=h. - : loop as
for(auto it = lowerbound(l); it <= lowerbound(h); ++it) {}. This workslowerbound(h)first first index>= h, so we don't include any=h. - : use
for(auto it = upperbound(l); it <= upperbound(h); ++it) {}.upperbound(l)finds first index>l, so we ignore values=l. - : use
for(auto it = upperbound(l); it < lowerbound(h); ++it) {}.
How to think about which one we want? This about it as lowerbound shifts
iterators towards the left, and upperbound shifts iterators to right.
- For
[L, we want to shift beginning leftwards, solowerbound(L). - For
(L, we want to shift beginning rightwards, soupperbound(L). - For
H], we want to shift ending rightwards, soupperbound(H). - For
H), we want to shift ending leftwards, solowerbound(H).
§ equal_range
- To unify the above description, one can simply use
std::equal_range(fst, last, val)which returns the half-open interval[l, r)where the array has valueval. This is equivalent to returning a pair oflower_bound,upper_bound.