lower_bound() in C++ - 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';

Related

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.

Find the first element strictly less than a key in a vector sorted in descending order

I understand that this task can be accomplished using the find_if() STL-Algorithm function as follows:
long long int k; //k = key
scanf("%lld",&k);
auto it = find_if(begin(v),end(v),[k](auto e){return e<k;});
However I require the result to be obtained in logarithmic time. Since the vector is already sorted in descending order I'd like to use a binary search approach.
I understand the STL Algorithm function lower_bound and upper_bound guarantee a logarithmic complexity. However I'm unable to figure out how to use these functions to obtain the first element less than a key as opposed to the first element greater than or equal to a key.
For instance:
Suppose my vector contents are: 21 9 8 7 6 4
My key is : 10
I would want the output to be 9, since its the first element in a left to right scan of the vector that is less than 10.
Any help in this regard would be very helpful!
Thanks
You can use the standard algorithm std::upper_bound with the functional object std::greater.
Here is an example how it can be done.
#include <iostream>
#include <iterator>
#include <functional>
#include <algorithm>
int main()
{
int a[] = { 21, 9, 8, 7, 6, 4 };
int key = 10;
auto it = std::upper_bound(std::begin(a), std::end(a),
key, std::greater<int>());
if (it != std::end(a)) std::cout << *it << std::endl;
}
The program output is
9

Find elements in a vector which lie within specified ranges

I have a vector of integer elements in sorted. An example is given below:
vector<int> A ={3,4,5,9,20,71,89,92,100,103,109,110,121,172,189,194,198};
Now given the following "start" and "end" ranges I want to find out which elements of vector A fall into the start and end ranges.
int startA=4; int endA=8;
int startB=20; int endB=99;
int startA=120; int endC=195;
For example,
elements lying in range startA and startB are: {4,5}
elements lying in range startA and startB are: {20,71,89,92}
elements lying in range startC and startC are: {121,172,189,194}
One way to do this is to iterate over all elements of "A" and check whether they lie between the specified ranges. Is there some other more efficient way to find out the elements in the vector satisfying a given range
One way to do this is to iterate over all elements of "A" and check whether they lie between the specified ranges. Is there some other more efficient way to find out the elements in the vector satisfying a given range
If the vector is sorted, as you have shown it to be, you can use binary search to locate the index of the element that is higher than the lower value of the range and index of element that is lower than the higher value of the range.
That will make your search O(log(N)).
You can use std::lower_bound and std::upper_bound, which requires the container to be partially ordered, which is true in your case.
If the vector is not sorted, linear iteration is the best you can do.
If the vector is sorted all you need to do is to use dedicated functions to find your start range iterator and end range iterator - std::lower_bound and std::upper_bound. Eg.:
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> A ={3,4,5,9,20,71,89,92,100,103,109,110,121,172,189,194,198};
auto start = std::lower_bound(A.begin(), A.end(), 4);
auto end = std::upper_bound(A.begin(), A.end(), 8);
for (auto it = start; it != end; it++) {
std::cout << *it << " ";
}
std::cout << std::endl;
}
//or the C++1z version (works in VS2015u3)
int main() {
std::vector<int> A ={3,4,5,9,20,71,89,92,100,103,109,110,121,172,189,194,198};
std::copy(std::lower_bound(A.begin(), A.end(), 4),
std::upper_bound(A.begin(), A.end(), 8),
std::ostream_iterator<int>(cout, " "));
std::cout << std::endl;
}
This however will work only if startX <= endX so you may want to test the appropriate condition before running it with arbitrary numbers...
Searching bound iterators using std::lower_bound and std::upper_bound will cost O(log(N)) however it has to be stated that iterating through the range of elements in average case is O(N) and the range may contain all the elements in your vector...
The best way I can think is to apply modified binary search twice and find two indices in the vector arr and then print all items in between this range . Time complexity will be O(log n).
A modified form of binary search looks like:(PS its for arrays, also applicable for vector):
int binary_search(int *arr,int start,int end,int key)
{
if(start==end)
{
if(arr[start]==key){return start+1;}
else if(arr[start]>key&&arr[start-1]<=key){return start;}
else return 0;
}
int mid=(start+end)/2;
if(arr[mid]>key && arr[mid-1]<=key)return mid;
else if(arr[mid]>key)return binary_search(arr,start,mid-1,key);
else return binary_search(arr,mid+1,end,key);
}
If range of integers of vector A is not wide, bitmap is worth the consideration.
Let's assume all integers of A are positive and are in between 0 ... 1024, the bitmap can be built with:
#include <bitset>
// ...
// If fixed size is not an option
// consider vector<bool> or boost::dynamic_bitset
std::bitset<1024> bitmap;
for(auto i : A)
bitmap.set(i);
That takes N iterations to set bits, and N/8 for storing bits. With the bitmap, one can match elements as follows:
std::vector<int> result;
for(auto i = startA; i < endA; ++i) {
if (bitmap[i]) result.emplace_back(i);
}
Hence speed of the matching depends on size of range rather than N. This solution should be attractive when you have many limited ranges to match.

c++ STL remove-if algorithm and erase algorithm issue.

Aim : Create a vector. Use remove_if on it
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
#include<functional>
using namespace std;
int main()
{
int negative_count=0;
vector<int> v = { 2, -1, -3, 5, -5, 0, 7 };
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
vector<int>::iterator new_it=remove_if(v.begin(), v.end(), bind2nd(greater<int>(), -1));
v.erase(new_it);
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}
The output:
The remove_if condition is to remove numbers greater than -1.
Why is it displaying -5 twice?The output after remove_if should be -1 -3 -5 5 0 7 according to me.
Also if i use
V.erase(new_int,v.end())
The output is fine: -1 -3 -5
When you call std::remove/remove_if, it moves elements which don't satisfy the condition to the front of the range. The values of any remaining elements (starting from the position of the returned iterator) are unspecified. Some people seem to think that it swaps the elements such that the ones which satisfy the condition are moved to the back. But the algorithm is not specified to do this. If that's the result you want, then the algorithm you are looking for is std::partition.
The information said replace_if returns a pointer to a new range,So i expected the new range after my output
remove_if returns an iterator.
Namely a one past the end iterator of the range containing only elements that do NOT satisfy the condition. There is no guarantee that the rest of the range will contain all other elements.
std::vector<int> v{ 2, -1, -3, 5, -5, 0, 7 };
auto new_end = std::remove_if(v.begin(), v.end(), [](auto i){ return i > -1; });
// now the range [v.begin(), new_end) contains only elements that are not > -1
// contents of [new_end, v.end()) are unspecified
for(auto i = v.begin(); i!=new_end; ++i)
{
std::cout << *i;
}
erase-remove idiom requires you to specify the whole range of elements to be removed.
Thats because you'd require every item that does match the condition to be removed. not only one.
v.erase(new_end, v.end());
Erase elements Removes from the vector either a single element
(position) or a range of elements ([first,last)).
Above reference is from http://www.cplusplus.com/reference/vector/vector/erase/
This means that in your case, you only erase one element from the vector which is pointed by the iterator returned by remove_if() function. You need to define a ranged as you mentioned at the end:
V.erase(new_int,v.end())
Because remove_if doesn't actually remove anything, it only copies/moves elements satisfying predicate to the end. So you have to write v.erase(new_it, v.end()).
Link

lower_bound == upper_bound

What does lower_bound mean. If I had to guess I would answer that this function returns the iterator at the last element that is less than the value asked for. But I see that lower_bound is almost the same as upper_bound. The only difference is strict inequality in the case of upper_bound. Is there a true lower bound selection function in stl that agrees with the normal definition of lower bound.
EDIT: It was too many negations in the docs which made me confused. The problem was that I got the same iterator. I solved it by subtracting 1 from lower_bound return value. I use it for interpolation:
float operator()(double f)
{
SpectrumPoint* l=std::lower_bound(beginGet(),endGet(),(SpectrumPoint){float(f),0.0f}
,SpectrumPoint::CompareFreqLessThan);
if(l>beginGet())
{--l;}
SpectrumPoint* u=std::lower_bound(beginGet(),endGet(),(SpectrumPoint){float(f),0.0f}
,SpectrumPoint::CompareFreqLessThan);
if(u==endGet())
{u=beginGet();}
if(l==u)
{
if(u==endGet())
{return u->amp;}
return l->amp;
}
double f_min=l->freq;
double A_min=l->amp;
double f_max=u->freq;
double A_max=u->amp;
double delta_f=f_max-f_min;
double delta_A=A_max-A_min;
return A_min + delta_A*(f-f_min)/delta_f;
}
I am sorry for this confusion :-(
Lower bound: first element that is greater-or-equal.
Upper bound: first element that is strictly greater.
Example:
+- lb(2) == ub(2) +- lb(6) +- lb(8)
| == begin() | == ub(6) | +- ub(8) == end()
V V V V
+---+---+---+---+---+---+---+---+---+---+---+
| 3 | 4 | 4 | 4 | 4 | 5 | 7 | 7 | 7 | 7 | 8 |
+---+---+---+---+---+---+---+---+---+---+---+
^ ^ ^
| | |
+- lb(4) +- ub(4) +- lb(9) == ub(9) == end()
|- eq-range(4) -|
As you can see, the half-open equal-range for n is [lb(n), ub(n)).
Note that both bounds give you meaningful insertion locations for an element of the desired value so that the ordering is maintained, but lower_bound has the distinguishing feature that if the element already exists, then you get an iterator which actually points to that element. Thus you can use lower_bound on an ordered range to implement your own unique-membership or multiple-membership container.
void insert(Container & c, T const & t)
{
auto it = std::lower_bound(c.begin(), c.end(), t);
// if unique container:
if (it != c.end() && *it == t) { /* error, element exists! */ return; }
c.insert(it, t);
}
It returns the iterator one past the last element that is less than the value asked for. This is useful as an insertion position (and that's why the function returns that iterator). It's also useful that the half-open range first, lower_bound(first, last, value) specifies all values less than value.
upper_bound returns the iterator one past the last element [less than or equal to / not greater than] the value asked for. Or strictly: the last element which the value is not less than, since both algorithms deal exclusively in less-than comparators.
If you want the iterator before the iterator returned by lower_bound, you can subtract 1 (for a random access iterator), decrement (for a bidirectional iterator), or do a linear search instead of using lower_bound (for a forward iterator that is none of those).
Beware the edge case that there is no element less than the value asked for, in which case you can't have what you want, because it doesn't exist. lower_bound of course returns the beginning of the range in that case, so doesn't need a special-case return value.
Since this has been reopened, I'll try to make my comment an answer.
The name lower_bound is mathematically incorrect. A better name might be least_upper_bound, but that would probably confuse most non-mathematically minded folk. (And then what do you call upper_bound? almost_least_upper_bound? Yech!)
My advice: Get over the fact that the names lower_bound and upper_bound are technically incorrect. The two functions as defined are quite useful. Think of those functions as a useful abuse of notation.
To make a mathematically correct lower_bound function that conforms with the C++ concept of an iterator, the function would have to return a reverse iterator rather than a forward iterator. Returning a reverse iterator is not nearly as useful as the approach taken by the perhaps misnamed lower_bound and upper_bound, and the concept of returning a reverse iterator runs afoul of the fact that not all containers are reversible.
Why a reverse iterator? Just as there is no guarantee that an upper bound exists in the container, there similarly is no guarantee that a lower bound will exist. The existing lower_bound and upper_bound return end() to indicate that the searched-for value is off-scale high. A true lower bound would need to return rend() to indicate that the searched-for value is off-scale low.
There is a way to implement a true lower bound in the form of a forward iterator, but it comes at the price of abusing the meaning of end() to mean "there is no lower bound". The problem with this abuse of notation is that some user of the function might do something equivalent to true_lower_bound(off_scale_low_search_value)-1 and voila! one has a pointer to the largest element in the set.
That said, here's how to do it. Have the true lower bound function return end() if the container is empty or if the searched-for value is smaller than the first value in the container. Otherwise return upper_bound()-1.
lower_bound, upper_bound and equal_range are functions which perform binary search in a sorted sequence. The need for three functions comes from the fact that elements may be repeated in the sequence:
1, 2, 3, 4, 4, 4, 5, 6, 7
In this case, when searching for the value 4, lower_bound will return an iterator pointing to the first of the three elements with value 4, upper_bound will return an iterator pointing to the element with value 5, and equal_range will return a pair containing these two iterators.
Following David Hammen's answer, I attempted to explain why we often don't feel the names of lower_bound/upper_bound to be correct, or at least intuitive.
It's because we are looking for an element immediately lower than the query.
I made a drawing and a use case:
Code:
template< typename T, typename U >
auto infimum(std::map<T,U> const& ctr, T query)
{
auto it = ctr.upper_bound(query);
return it == ctr.begin() ? ctr.cend() : --it;
}
template< typename T, typename U >
bool is_in_interval(std::map<T,U> const& ctr, T query)
{
auto inf = infimum(ctr, query);
return inf == ctr.end() ? false : query <= inf->second;
}
https://ideone.com/jM8pt3
Basically to get the behavior of the "grey arrows", we need upper_bound - 1 which is why it's weird.
Let me rephrase that slightly: from the name lower_bound we instinctively expect returns-first-immediately-inferior-element (like the grey arrows). But we get returns-first-immediately-superior-element for lower_bound; and first-immediately-strictly-superior-element for upper_bound. That's what is surprising.
It's surprising in the hypothesis that you work with a sparse sequence like my thought experiment in the picture above. But it makes wonderful sense when you think of it in terms of «bounds of an equal_range» in a dense sequence, populated with plateaus, like Kerrek SB beautifully pictured.
Test code:
#include <map>
#include <cassert>
#include <iostream>
// .. paste infimum and is_in_interval here
int main()
{
using std::cout;
using Map = std::map<int,int>;
Map intervals{{2,5}, {8,9}};
auto red = infimum(intervals, 4);
assert(red->first == 2);
cout << "red->first " << red->first << "\n";
auto green = infimum(intervals, 6);
assert(green->first == 2);
cout << "green->first " << green->first << "\n";
auto pink = infimum(intervals, 8);
assert(pink->first == 8);
cout << "pink->first " << pink->first << "\n";
auto yellow = infimum(intervals, 1);
assert(yellow == intervals.cend());
auto larger_than_all = infimum(intervals, 15);
assert(larger_than_all->first == 8);
bool red_is = is_in_interval(intervals, 4);
cout << "red is in " << red_is << "\n";
bool green_is = is_in_interval(intervals, 6);
cout << "green is in " << green_is << "\n";
bool pink_is = is_in_interval(intervals, 8);
cout << "pink is in " << pink_is << "\n";
bool yellow_is = is_in_interval(intervals, 1);
cout << "yellow is in " << yellow_is << "\n";
}
results in
red->first 2
green->first 2
pink->first 8
red is in 1
green is in 0
pink is in 1
yellow is in 0
seems ok.
So of course the utility functions are not very good, they should be designed with a range API, so we can work with any collection or sub-range, or reverse iterators, or filtered views and whatnot. We can get that when we have C++20. In the meantime, I just made a simple educative map-taking API.
play with it:
https://ideone.com/jM8pt3
Another usage of lower_bound and upper_bound is to find a range of equal elements in a container, e.g.
std::vector<int> data = { 1, 1, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6 };
auto lower = std::lower_bound(data.begin(), data.end(), 4);
auto upper = std::upper_bound(lower, data.end(), 4);
std::copy(lower, upper, std::ostream_iterator<int>(std::cout, " "));
Auch!
Did you change the original code or is the copy-paste error in there since day one?
float operator()(double f)
{
SpectrumPoint* l=std::lower_bound//...
...
SpectrumPoint* u=std::lower_bound//...
...
}
In the code I read today you are assigning lower_bound to both 'l' and 'u'.