Difference between upper_bound and lower_bound in stl - c++

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?

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

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.

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

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

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]

Related

Using comparator in upper_bound STL

I'm trying to make a program that gives the last element that is less than or equal to our given value.
According to the definition of lower_bound, it gives the first element that is greater than or equal to the given key value passed. I created a comparator function
bool compare(int a, int b) {
return a <= b;
}
This was passed in my lower bound function:
int largest_idx = lower_bound(ic, ic + n, m, compare)
On execution, it was giving me the last element which was less than equal to my m (key value). Isn't this opposite to how lower_bound works ? Lower bound is supposed to give me the first value for my comparison or does the comparator actually change that?
If you want to turn "first" into "last", you have two options. First, you can use std::upper_bound and then take the previous element (see below). Second, you can use reverse iterators:
const auto pos = std::lower_bound(
std::make_reverse_iterator(ic + n),
std::make_reverse_iterator(ic), m, compare);
where compare is
bool compare(int a, int b) {
return b < a;
}
With this comparator, std::lower_bound() returns the iterator pointing to the first element that is not greater (= less than or equal) than m. On the reversed range this is equivalent to returning the iterator pointing to the last element satisfying this criterion in the original range.
Simple example:
int ic[] = {1, 3, 3, 5};
// pos
// m = 1 ^
// m = 2 ^
// m = 3 ^
How do I modify that search criteria (change <= to something else)?
std::lower_bound finds the first element in the range (partitioned by the comparator into true, ..., true, false, ... false), for which the comparator returns false. If your criterion can be rephrased in this language, you can use std::lower_bound.
Suppose we have a range 1 3 3 5 and we replace < with <= (your version of compare). Then we have:
1 3 3 5
m = 2 T F F F
m = 3 T T T F
m = 4 T T T F
For m = 3 and m = 4, std::lower_bound will return the iterator to 5, i.e. past the last 3. In other words, std::lower_bound with default < being replaced with <= is exactly what std::upper_bound with default < is. You can advance the resulting iterator by -1 to get the last element (but be careful about corner cases like m = 0 in this example).
How do I change whether I want the first or last element
It always returns the first element for which the comparator returns false. You can either reverse the range or find the first element that follows the one you want to find.
The comparator must not check for equality, use less than.
Also the data shall already be sorted or must at least be partitioned according to the comparator.
cf. https://www.cplusplus.com/reference/algorithm/lower_bound/

lower_bound() in C++

From reading from the Internet, I understand that The lower_bound() method in C++ is used to return an iterator pointing to the first element in the range [first, last) which has a value not less than value. This means that the function returns the index of the next smallest number just greater than that number.
So, for the given code below I understood that the output is 3. But, as there is repetition of 6. How can I get the index of last 6 using lower_bound(). I can implement my own binary_search() for that, but I want to know how to do it by lower_bound().
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int array[] = {5,6,7,7,6,5,5,6};
vector<int> v(array,array+8); // 5 6 7 7 6 5 5 6
sort (v.begin(), v.end()); // 5 5 5 6 6 6 7 7
vector<int>::iterator lower,upper;
lower = lower_bound (v.begin(), v.end(), 6);
upper = upper_bound (v.begin(), v.end(), 6);
cout << "lower_bound for 6 at position " << (lower- v.begin()) << '\n';
return 0;
}
Use pair of lower_bound and upper_bound. Or one equal_range -- that would be more optimal.
Both upper_bound and high part of equal_range would be past the last "6". The same as end is not last, it is past the last.
You can use reverse iterators into the vector, but then to fulfill the ordering requirement for std::lower_bound you need to inverse the comparison, so you need to use std::greater instead of the default std::less. This however also means that now you are not really looking for a lower bound, but for an upper bound with respect to that comparison function, so:
auto upper = std::upper_bound(v.rbegin(), v.rend(), 6, std::greater{});
If the array is sorted, iterating between lower_bound and upper_bound you get all elements which equal your pivot point:
lower = lower_bound(v.begin(), v.end(), 6);
upper = upper_bound(v.begin(), v.end(), 6);
for (auto it = lower; it != upper; it++) {
assert(6 == *it);
}
The question you are asking, i.e. what is the index of the last 6, doesn't have a corresponding function in the standard library because is ill-defined in the case when the range doesn't contain any 6. In all other cases since you have a random access container you can get an iterator to the last 6 by removing one from upper_bound (upper - 1 in your code), in the same way you get the last index of an array by removing 1 from length.
However I suggest you avoid relying on the position of the last element equal when you design your algorithm. Also note that if you need both lower and upper bound you can get both at the same time with equal_range, which may even perform better because it may be optimised to only traverse the data structure once:
std::tie(lower,upper) = equal_range(v.begin(), v.end(), 6);
for (auto it = lower; it != upper; it++) {
assert(6 == *it);
}
You can use lower_bound again, updating the begin and the value:
auto lower = std::lower_bound (v.cbegin(), v.cend(), 6);
auto upper = std::lower_bound (lower, v.cend(), 6 + 1);
std::cout << "Number of values found: " << std::distance(lower, upper) << '\n';

lower_bound() giving unexpected result

I wrote a code where I need to find lower_bound from square number sequence. But lower bound giving me result for upper_bound.
Here is my code & compiler link: http://cpp.sh/3cppb
// Example program
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::vector<int> v{ 1, 4, 9, 16, 25 }; // all the square numbers
int x = std::lower_bound(v.begin(), v.end(), 5) - v.begin() ;
std:: cout<<"Postion "<<x<< " value "<<v[x] <<std::endl; //getting output for upperbound
}
Output:
Postion 2 value 9
Expected Output
Postion 1 value 4
std::lower_bound returns the iterator to the first element which is greater or equal to the target value:
Returns an iterator pointing to the first element in the range [first,
last) that is not less than (i.e. greater or equal to) value, or last
if no such element is found.
As 9 is the first value which is greater or equal to 5 (it is greater, of course), the result is totally correct.
If you tried to find an element which is already in v, like 9, then you would get different results for std::lower_bound and std::upper_bound:
std::distance(begin(v), std::lower_bound(begin(v), end(v), 9)); // 2
std::distance(begin(v), std::upper_bound(begin(v), end(v), 9)); // 3
std::lower_bound is working correctly. The function returns the first element that is not less than the value provided. Since 9 is the first value that is not less than 5 you get that element.
std::upper_bound in this case will return the same element as it returns the first element greater than the specified value. Where you will see a difference is cases like
std::vector data = {4,4,4};
auto low = std::lower_bound(data.begin(), data.end(), 4);
auto high = std::upper_bound(data.begin(), data.end(), 4);
In this case low will be begin() as 4 is not less than 4 while high will be end() as there is no element greater than 4 in the vector.
The quotation from the Standard, [lower.bound]:
template<class ForwardIterator, class T>
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value);
Returns: The furthermost iterator i in the range [first,last] such that for every iterator j in the range [first,i) the following corresponding conditions hold: *j < value.

Upper/lower bounds don't work as I expect, can not understand why

Here is the code. As a result I get "4 4". Don't understand why it is not "2 4" (according to lower and upper bounds' defenitions).
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<int> v = {1, 2, 4, 5};
vector<int>::iterator s , f;
s = lower_bound(v.begin(), v.end(), 3);
f = upper_bound(v.begin(), v.end(), 3);
cout << (*s) << " " << (*f);
return 0;
}
From std::lower_bound:
Returns an iterator pointing to the first element in the range
[first,last) which does not compare less than val.
The first element (from the beginning of the vector) which is not less than 3 is 4 and hence lower_bound returns 4.
From std::upper_bound:
Returns an iterator pointing to the first element in the range [first,last) which compares greater than val.
The first element (from the beginning of the vector) which is greater than 3 is 4 and hence upper_bound returns 4.
The reason for this confusion is because upper_bound returns the first element that is greater than the given value, so by symmetry we expect lower_bound to return the last element (from the beginning of the vector) that is less than the given value. But alas, the std function doesn't obey this "expected" symmetry.
It would be easier to understand/remember what std::lower_bound() and std::upper_bound() return knowing that std::equal_range() returns a pair of iterators, where the first one is equal to what std::lower_bound() returns, and the second one is equal to what std::upper_bound() returns.
So, here are different cases when they are called with a parameter of 4:
1 2 3 4 4 4 4 5 E
| |
F S - first points to the first element, second to the one behind last, representing range which contains 4
1 2 3 4 5 E
| |
F S same for one element
1 2 3 4 E
| |
F S same as before, but 4 is the last element
1 2 3 5 E
|
F==S first == second, which means range for elements equal to 4 is empty
1 2 3 E
|
F==S same as before but there is no element greater than 4
Where E means what container.end() returns - an iterator behind the last element.
The naming of lower_bound and upper_bound is unfortunate as it invites confusion. The names refer to the results when searching through a sequence that has multiple elements that are exactly equivalent to the one you're searching; lower_bound returns the iterator to the start, and upper_bound returns one past the end.
When the element isn't part of the sequence, they both return an iterator to the first element greater than the one you were searching for. This might be the end iterator if there are none greater.

Searching for a range [x,y] in a sorted vector in C++ [using lower_bound() and upper_bound() ]

I have an array of sorted vectors,
vector< int> b[1000009];
Now I have to search the range between x and y inclusive in the row b[factor].
'factor', 'x' and 'y' are all integers. I have used the following approch :
int lb,ub;
if(b[factor][0]>=x){lb=0;}
else
{
lb=upper_bound(b[factor].begin(),b[factor].end(),x)-b[factor].begin();
while(b[factor][lb-1]>=x)lb--;
}
if(b[factor][sz2-1]<=y)
{
ub=sz2-1;
}
else {
ub=lower_bound(b[factor].begin(),b[factor].end(),y)-b[factor].begin();
while(b[factor][ub]>y)ub--;
}
But this approach ain't giving correct answers all the time. And besides I would like to used some comparator functions to achieve the same. This is my first time with lower_bound() and upper_bound(). So please tell me how to implement the comparator function here.
std::lower_bound returns the position of the first element whose value is greater than or equal to the argument. std::upper_bound returns the position of the first element that is greater than the argument. You can use these to iterate over the range of values between x and y like this:
auto vb = b[factor].begin();
auto ve = b[factor].end();
auto lb = lower_bound(vb,ve,x);
auto ub = upper_bound(vb,ve,y);
for (auto i=lb; i!=ub; ++i) {
// Do something with *i
}
Let's take this example. Say our vector contains these values:
1 3 4 7 9
And let's say x=3 and y=7. std::lower_bound(vb,ve,x) will return the position of the first value that is greater than or equal to 3. Since there is a value that is equal to 3, its position is what we will get for the lower bound.
std::upper_bound(vb,be,y) will return the position of the first value that is greater than 7. That would be the position of 9 in this case.
So our loop is going from the position of 3 up to, but not including, the position of 9, which is exactly the range of values that we want.
Now what if x=5 and y=6. There would be no values in that range. What would it do?
The first value that is greater than or equal to 5 is 7. The first value that is greater than 6 is also 7. So lb and ub would be the same position! Our loop would terminate immediately, which is exactly what we want since there are no elements in our range.