1

I understood the concept of Lower and Upper found for an Increasing/Ascending array. i.e

  1. Lower Bound: iterator pointing to the first element in the range [first, last) >= Value
  2. Upper Bound: iterator pointing to the first element in the range [first, last) > Value

Below is my code for Decreasing/Non-ascending vector in which I am facing issue:

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

int main()
{
    vector<int> vec = {45,40,35,12,6,3};

    auto itr3 = lower_bound(vec.begin(),vec.end(),40);
    auto itr4 = upper_bound(vec.begin(),vec.end(),40);

    if(itr3 == vec.end() && itr4 == vec.end())
        cout<<"Lower & Upper Bound not Found\n";
    else
    {
        cout <<"lower Bound of 40 :"<<*itr3<<endl;
        cout <<"Upper Bound of 40 :"<<*itr4<<endl;
    }

    return 0;
}

The Output is:

Lower & Upper Bound not Found.

But as mentioned above the output should be something like :

lower Bound of 40 :40
Upper Bound of 40 :45

Please help me understood his behavior of lower and upper bound in case of decreasing/non-ascending vectors.

underscore_d
  • 6,309
  • 3
  • 38
  • 64
MARCOS
  • 21
  • 1
  • 7
  • 1
    `lower_bound()` and `upper_bound()` depend on a specific order. By default, it's that of `std::less()` for the data type. Your vector explicitily doesn't provide this. Either, use it backwards (i.e. `rbegin()` and `rend()`) or provide a custom predicate which reflects the order you've chosen. – Scheff's Cat May 26 '21 at 12:52

3 Answers3

3

The target of std::lower_bound and std::upper_bound have to be increasing (non-decreasing) order.

You can change the definition of "increasing" by specifying a comparator by the 4th argument of the functions.

You can use std::greater to work with descending vectors.

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>

using namespace std;

int main()
{
    vector<int> vec = {45,40,35,12,6,3};

    auto itr3 = lower_bound(vec.begin(),vec.end(),40,std::greater<int>());
    auto itr4 = upper_bound(vec.begin(),vec.end(),40,std::greater<int>());

    if(itr3 == vec.end() && itr4 == vec.end())
        cout<<"Lower & Upper Bound not Found\n";
    else
    {
        cout <<"lower Bound of 40 :"<<*itr3<<endl;
        cout <<"Upper Bound of 40 :"<<*itr4<<endl;
    }

    return 0;
}
underscore_d
  • 6,309
  • 3
  • 38
  • 64
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
3

You can use reverse iterators to get the 40/45 result:

#include <algorithm>
#include <cstdio>
#include <vector>

int main() {
  std::vector<int> const vec = { 45, 40, 35, 12, 6, 3 };

  auto const it_lb = std::lower_bound(vec.rbegin(), vec.rend(), 40);
  auto const it_ub = std::upper_bound(vec.rbegin(), vec.rend(), 40);

  std::printf("Lower: %d\nUpper: %d\n", *it_lb, *it_ub);
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
0

You need to use another overloaded declarations of the algorithms std::lower_bound and std::upper_bound with a comparison function as for example the standard function object std::greater.

Here is a demonstrative program.

#include <iostream>
#include <functional>
#include <vector>
#include <iterator>
#include <algorithm>


int main() 
{
    std::vector<int> vec = { 45, 40, 35, 12, 6, 3 };
    
    auto lower_bound = std::lower_bound( std::begin( vec ),
                                         std::end( vec ),
                                         40,
                                         std::greater<int>() );

    auto upper_bound = std::upper_bound( std::begin( vec ),
                                         std::end( vec ),
                                         40,
                                         std::greater<int>() );
                                         
    std::cout << *lower_bound << " <-> " << *upper_bound << '\n';
    
    return 0;
}

The program output is

40 <-> 35

I have not checked the returned iterators in the program whether they are equal to the iterator returned by std::end( vec ) for simplicity.

Instead of the standard function object std::greater you can use your own lambda-expression. For example

auto descending = []( const auto &x, const auto &y )
                  {
                    return y < x;
                  };
                  
auto lower_bound = std::lower_bound( std::begin( vec ),
                                     std::end( vec ),
                                     40,
                                     descending );

auto upper_bound = std::upper_bound( std::begin( vec ),
                                     std::end( vec ),
                                     40,
                                     descending );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335