28

I was looking at how the upper_bound and lower_bound algorithms work in stl on these pages: lower_bound, upper_bound, and it's documented the same way on these pages: lower_bound, upper_bound

Looking at the code from the links, they seem to do exactly the same thing to me, with only the following lines being different (looking at the code from the first 2 links):

lower_bound (line 10):

if (*it<val) {                 // or: if (comp(*it,val)), for version (2)

upper_bound (line 10):

 if (!(val<*it))                // or: if (!comp(val,*it)), for version (2) 

but surely reversing the compared elements and then comparing them to false is a double negative, and thus they do exactly the same thing?

Is there actually a difference that I'm just not seeing, Is this an error in the documentation on the websites? If the latter, what would be the correct way?

xEric_xD
  • 506
  • 1
  • 5
  • 12
  • 9
    `!(val<*it)` would be `*it <= val`, and not `*it < val`. – Jarod42 Jan 31 '17 at 13:19
  • 1
    @Jarod42 ah of course, I overlooked that. – xEric_xD Jan 31 '17 at 13:20
  • 5
    I like the SGI STL descriptions: [`lower_bound`: the first position where `value` could be inserted without violating the ordering](http://www.sgi.com/tech/stl/lower_bound.html), [`upper_bound`: the last position where `value` could be inserted without violating the ordering](http://www.sgi.com/tech/stl/upper_bound.html). Which is exactly what the names mean. They return either the lower bound (i.e. the start) or upper bound (i.e. one past the end) of the range of elements _equivalent to_ the specified `value`. And `equal_range` gives you both positions, as a pair `[lower,upper)`. – Jonathan Wakely Jan 31 '17 at 13:25

5 Answers5

64
value a a a b b b c c c
index 0 1 2 3 4 5 6 7 8
bound       l     u

Where l represents the lower bound of b, and u represents the upper bound of b.

So if there are range of values that are "equal" with respect to the comparison being used, lower_bound gives you the first of this, upper_bound gives you one-past-the-end of these. This is the normal pattern of STL ranges [first, last).

BoBTFish
  • 19,167
  • 3
  • 49
  • 76
  • 1
    Thanks, I overlooked that fact that it also compares for equal elements in upper_bound. I'll accept your answer when possible. – xEric_xD Jan 31 '17 at 13:23
  • 7
    Nice and clear explanation. I think it would be even better if you add an example for the case when `b` does not exist in the list, e.g. `a a a c c c c`. – Setyo N Dec 04 '18 at 22:35
35

A simple answer is and less confusing WAY to remember this is below

std::lower_bound - returns iterator to first element in the given range which is EQUAL_TO or Greater than val.

std::upper_bound - returns iterator to first element in the given range which is Greater than val.

Ruben Helsloot
  • 12,582
  • 6
  • 26
  • 49
8

lower_bound:

Returns an iterator pointing to the first element in the range [first,last) which does not compare less than val.

upper_bound:

Returns an iterator pointing to the first element in the range [first,last) which compares greater than val.

Now there is a difference between being no less than something and greater than something.

For example, if you compare 4 and 5, you can say that

5 is _not less than_ 4
5 is _greater than_  4

However if you compare you compare 4 and 4:

4 is _not less than_    4
4 is _not greater than_ 4
SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
4

A simple answer from vscode

lower_bound: find the first pos in which val could be inserted without changing the order

upper_bound: find last postion in which val could be inserted without changing the order

  • Even though I think this might not be the gold standard way to "define" it, I think it's useful to remember this trick in competitive/interview programming! Thanks :) – Niraj Pandkar Nov 15 '21 at 20:53
2

The simple answer is [ lower_bound, upper_bound )

s.lower_bound(t) will return iterator to the first element v in set such that v >= t
s.upper_bound(t) will return iterator to the first element v in set such that v > t.

When we often call xxxxx_bound for the STL set or map,
we often want to find the data in some range.

I share some usages of lower_bound & upper_bound samples here. So it could be easy for everyone to use it and remember it.

iterate all values in [A, B)

set<int> s = {0,1,2,10,11,12,15};
int A=1, B=11;
for(auto iter = s.lower_bound(A); iter != s.lower_bound(B); iter++) {
    cout<<*iter<<"\t";
}

Result

1       2       10

It show all v in set s satsify 1 < v <= 11 a.k.a all v in [1, 11)

iterate all values in [A, B]

set<int> s = {0,1,2,10,11,12,15};
int A=1, B=11;
for(auto iter = s.lower_bound(A); iter != s.upper_bound(B); iter++) {
    cout<<*iter<<"\t";
}

Result

1       2       10      11

It show all v in set s satsify 1 <= v <= 11 a.k.a all v in [1, 11]

iterate all values in (A, B)

set<int> s = {0,1,2,10,11,12,15};
int A=1, B=11;
for(auto iter = s.upper_bound(A); iter != s.lower_bound(B); iter++) {
    cout<<*iter<<"\t";
}

Result

2       10

It show all v in set s satsify 1 < v < 11 a.k.a all v in (1, 11)

Iterate all values in (A, B]

set<int> s = {0,1,2,10,11,12,15};
int A=1, B=11;
for(auto iter = s.upper_bound(A); iter != s.upper_bound(B); iter++) {
    cout<<*iter<<"\t";
}

Result

2       10      11

It show all v in set s satsify 1 < v <= 11 a.k.a all v in (1, 11]

Milo Chen
  • 3,617
  • 4
  • 20
  • 36