Using std:: lower_bound - c++

// lower_bound/upper_bound example
#include <iostream> // std::cout
#include <algorithm> // std::lower_bound, std::upper_bound, std::sort
#include <vector> // std::vector
int main () {
int myints[] = {10,20,30,30,20,10,10,20};
std::vector<int> v(myints,myints+8); // 10 20 30 30 20 10 10 20
std::sort (v.begin(), v.end()); // 10 10 10 20 20 20 30 30
std::vector<int>::iterator low,up;
low=std::lower_bound (v.begin(), v.end(), 20); // ^
up= std::upper_bound (v.begin(), v.end(), 20); // ^
std::cout << "lower_bound at position " << (low- v.begin()) << '\n';
std::cout << "upper_bound at position " << (up - v.begin()) << '\n';
return 0;
}
In this code can somebody please explain why we need to do (low - v.begin()) and (up - v.begin()) on the third and fourth lines from the bottom.
If I do
cout << low << endl;
I get the follwoing error which I dont understand
cannot bind ‘std::ostream {aka std::basic_ostream}’ lvalue to ‘std::basic_ostream&&’

*low *is an iterator as you declared. It holds the memory address that generates by your PC and you don't need any memory address to return . By writing
low- v.begin()
You make a command to your program to return the actual position of your searching query as an answer.
That's why it returns a value the
Address Position - Beginning of the Vector Position
Suppose your vector starting memory address is FFF1 and your searching value is at FFF8 ... Then it return FFF8 - FFF1 = 7 .. ( Example is just to illustrate )
That's how I understand .

The two subtractions are calculating the offset of the elements found at the positions low and up in the vector by calculating the delta between the iterator v.begin() and the iterators low and up, respectively. To make this code clearer, it probably would have been better to use std::distance.
When you tried to use cout << low << endl; you were trying to print out the value of the iterator. That's very different. Oh, and you're missing the std:: namespace reference around cout and endl.

Related

Unexpected behavior using `std::count` on `std::vector` of pairs

My goal is to completely remove all elements in a std::vector<std::pair<int, int>> that occur more than once.
The idea was to utilize std::remove with std::count as part of the predicate. My approach looks something like this:
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
using std::endl;
using i_pair = std::pair<int, int>;
int main()
{
std::vector<i_pair> vec;
vec.push_back(i_pair(0,0)); // Expected to stay
vec.push_back(i_pair(0,1)); // Expected to go
vec.push_back(i_pair(1,1)); // Expected to stay
vec.push_back(i_pair(0,1)); // Expected to go
auto predicate = [&](i_pair& p)
{
return std::count(vec.begin(), vec.end(), p) > 1;
};
auto it = std::remove_if(vec.begin(), vec.end(), predicate);
cout << "Reordered vector:" << endl;
for(auto& e : vec)
{
cout << e.first << " " << e.second << endl;;
}
cout << endl;
cout << "Number of elements that would be erased: " << (vec.end() - it) << endl;
return 0;
}
The array gets reordered with both of the (0,1) elements pushed to the end, however the iterator returned by std::remove points at the last element. This means that a subsequent erase operation would only get rid of one (0,1) element.
Why is this behavior occurring and how can I delete all elements that occur more than once?
Your biggest problem is std::remove_if gives very little guarantees about the contents of the vector while it is running.
It guarantees at the end, begin() to returned iterator contains elements not removed, and from there until end() there are some other elements.
Meanwhile, you are iterating over the container in the middle of this operation.
It is more likely that std::partition would work, as it guarantees (when done) that the elements you are "removing" are actually stored at the end.
An even safer one would be to make a std::unordered_map<std::pair<int,int>, std::size_t> and count in one pass, then in a second pass remove everything whose count is at least 2. This is also O(n) instead of your algorithms O(n^2) so should be faster.
std::unordered_map<i_pair,std::size_t, pair_hasher> counts;
counts.reserve(vec.size()); // no more than this
for (auto&& elem:vec) {
++counts[elem];
}
vec.erase(std::remove_if(begin(vec), end(vec), [&](auto&&elem){return counts[elem]>1;}), end(vec));
you have to write your own pair_hasher. If you are willing to accept nlgn performance, you could do
std::map<i_pair,std::size_t> counts;
for (auto&& elem:vec) {
++counts[elem];
}
vec.erase(std::remove_if(begin(vec), end(vec), [&](auto&&elem){return counts[elem]>1;}), end(vec));

Recieving "vector subscript out of range" only on visual studio if variable data contains an integer greater than all elements of vector?

cin >> q;
while (q--)
{
cin >> data;
//if this value is greater than all the elements of the vector throwing error
vector<int>::iterator low = lower_bound(v.begin(), v.end(), data); //does the lower bound
if (v[low - v.begin()] == data)
cout << "Yes " << (low - v.begin() + 1) << endl;
else
cout << "No " << (low - v.begin() + 1) << endl;// while this should be the output
}
if vector v contains 1 2 3 4 5 6 7 8
and we enter data 9
then its showing error as vector subscript out of range.
Per the std::lower_bound() documentation on cppreference.com:
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.
In your call to lower_bound(v.begin(), v.end(), data), when v is {1 2 3 4 5 6 7 8} and data is 9, there is no element in v that is >= data, so v.end() gets returned to low. As such, low - v.begin() is v.end() - v.begin(), which produces an index (8) that is out of bounds of the vector (valid indexes are 0-7). Which Visual Studio then warns you about.
You need to add a check for the condition when std::lower_bound() does not find a matching element:
auto low = lower_bound(v.begin(), v.end(), data);
if (low == v.end()) // <-- ADD THIS!
{
cout << "Not found" << endl;
}
else
{
auto index = low - v.begin();
if (v[index] == data)
cout << "Yes " << (index + 1) << endl;
else
cout << "No " << (index + 1) << endl;
}
Receiving “vector subscript out of range” only on visual studio ...
Visual Studio is correct in giving that assertion.
The debug version of the Visual C++ runtime will check the indices of std::vector, and will report issues if there is an out-of-bounds access.
The other compiler you're using is not reporting this error to you, since in reality operator [] for std::vector has undefined behavior if accessing an out-of-bounds item. Thus you are mistaken when you see the output -- your program has an off-by-one bug.
To prove this, here is your code, but it uses at() instead of [ ] to access the elements:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> v = {1,2,3,4,5,6,7,8};
std::vector<int>::iterator low = lower_bound(v.begin(), v.end(), 9);
if (v.at(low - v.begin()) == 9)
std::cout << "Yes " << (low - v.begin() + 1) << std::endl;
else
std::cout << "No " << (low - v.begin() + 1) << std::endl;// while this should be the output
}
Live Example
Note the std::out_of_range exception? You will now get that same error, regardless of the compiler you will use, since vector::at() does bounds checking.
Now here is your original code:
Original code
Note that you get the output, but you are "silently" accessing an out-of-bounds element, thus the behavior of the program is undefined.

C++ STL vector Deep erase

How to deep erase a vector?
Consider the following code.
#include<algorithm>
#include<iostream>
#include<iterator>
#include<vector>
using namespace std;
int main(){
vector<int> v {1,2,3,4,5};
for_each(begin(v),end(v),[&v](int& n){
static auto i = (int)0;
if(n == 2){
v.erase ( begin(v) +2, end(v));
}
cout << n << " having index " << i++ << endl;
});
v.erase ( begin(v) +2, end(v));
cout << v.size() << endl << v[4] << endl;
}
Output is
1 having index 0
2 having index 1
3 having index 2
4 having index 3
5 having index 4
2
4
What I want is accessing v[i] for any i from 2 to 4 to be invalid and compiler to throw an error.
In simpler words how to deep erase a vector?
You're triggering undefined behavior and therefore your results cannot be trusted.
If you need to check for boundaries use std::vector::at
vector<int> v{ 1,2,3,4,5 };
v.erase(begin(v) + 2, end(v));
try {
auto val = v.at(4);
} catch (std::out_of_range&) {
cout << "out of range";
}
Unless you code your own facility or workaround, you can't have such compile-time checks with std::vector. More information and some suggestions here: https://stackoverflow.com/a/32660677/1938163
I do not have time right now to give examples, but the only way I can think to cleanly do this is to either make a custom class to wrap or subclass vector. You could then produce a custom [] and at operators which throw an error on certain indexes. You could even have a deletion method which adds indeces to this list of banned ones.
Now if you need the error at compile time this is harder. I think something might be possible using a constexpr access operator and some static_asserts but I am not confident exactly how off hand.

Multiset Index Finding

I have a multi set of int . C++
multiset<int>t;
I need to find the position of the first element which is greater than of equal to val. I used lower_bound for this
multiset<int>::iterator it= lower_bound(t[n].begin(), t[n].end(), val);
but can not find the the relative position from the beginning of the multi set .
As The Cplusplus.com suggests using.. for vector.
// lower_bound/upper_bound example
#include <iostream> // std::cout
#include <algorithm> // std::lower_bound, std::upper_bound, std::sort
#include <vector> // std::vector
int main () {
int myints[] = {10,20,30,30,20,10,10,20};
std::vector<int> v(myints,myints+8); // 10 20 30 30 20 10 10 20
std::sort (v.begin(), v.end()); // 10 10 10 20 20 20 30 30
std::vector<int>::iterator low,up;
low=std::lower_bound (v.begin(), v.end(), 20); // ^
up= std::upper_bound (v.begin(), v.end(), 20); // ^
std::cout << "lower_bound at position " << (low- v.begin()) << '\n';
std::cout << "upper_bound at position " << (up - v.begin()) << '\n';
return 0;
}
Can I do it in multi set .. ?
Another question is : Can I merge to multi set like vectors like shown bellow , v1,v2,v are vectors ?
merge(v1.begin(),v1.end(),v2.begin(),v1.end(),back_inserter(v))
The generic way to get the distance between two iterators is to call std::distance.
auto it = std::lower_bound(t[n].begin(), t[n].end(), val);
const auto pos = std::distance(t[n].begin(), it);
For std::multiset, member types iterator and const_iterator are bidirectional iterator types. Bidirectional iterator does not support arithmetic operators + and - (for details check cppreference).
std::distance can be used to calculate the number of elements between two iterators.
std::distance uses operator- to calculate the number of elements if parameter is a random-access iterator. Otherwise, it uses the increase operator (operator++) repeatedly.
Here is a slightly changed code snippet from cppreference.
#include <iostream>
#include <set>
int main ()
{
std::multiset<int> mymultiset;
std::multiset<int>::iterator itlow, itup;
for (int i = 1; i < 8; i++) mymultiset.insert(i * 10); // 10 20 30 40 50 60 70
itlow = mymultiset.lower_bound(30);
itup = mymultiset.upper_bound(40);
std::cout << std::distance(mymultiset.begin(), itlow) << std::endl;
std::cout << std::distance(mymultiset.begin(), itup) << std::endl;
mymultiset.erase(itlow, itup); // 10 20 50 60 70
std::cout << "mymultiset contains: ";
for (std::multiset<int>::iterator it = mymultiset.begin(); it != mymultiset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
Output
2
4
mymultiset contains: 10 20 50 60 70
You can merge the std::multiset with std::multiset::insert member function as following;
#include <iostream>
#include <set>
int main ()
{
std::multiset<int> mset1;
std::multiset<int> mset2;
for (int i = 1; i < 8; i++) mset1.insert(i * 10); // 10 20 30 40 50 60 70
for (int i = 1; i < 8; i++) mset2.insert(i * 10); // 10 20 30 40 50 60 70
mset1.insert(mset2.begin(), mset2.end());
std::cout << "mset1 contains: ";
for (std::multiset<int>::iterator it = mset1.begin(); it != mset1.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
Output
mset1 contains: 10 10 20 20 30 30 40 40 50 50 60 60 70 70

Why hasn't sort_heap put the elements in the order I expected?

Given the following code:
// range heap example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool Greater(int a, int b)
{
if (a > b)
{
return true;
}
else
{
return false;
}
}
int main () {
int myints[] = {10,20,30,5,15};
vector<int> v(myints,myints+5);
//vector<int>::iterator it;
make_heap (v.begin(),v.end(), Greater);
cout << "initial min heap : " << v.front() << endl;
pop_heap (v.begin(),v.end(), Greater); v.pop_back();
cout << "min heap after pop : " << v.front() << endl;
v.push_back(9); push_heap (v.begin(),v.end(), Greater);
cout << "min heap after push: " << v.front() << endl;
sort_heap (v.begin(),v.end());
cout << "final sorted range :";
for (unsigned i=0; i<v.size(); i++) cout << " " << v[i];
cout << endl;
return 0;
}
why the return value is as follows:
initial min heap : 5
min heap after pop : 10
min heap after push: 9
final sorted range : 10 15 20 30 9 <= why I get this result, I expect 9 10 15 20 30.
If I call sort_heap(v.begin(), v.end(), Greater), then return value is 30 20 15 10 9.
Question > In this sample, I create a min-heap. Is this the reason that I cannot call sort_heap(v.begin(), v.end())?
thank you
sort_heap only sorts the range if it is heap-ordered according to the provided comparator. Since you used Greater as the comparator in all the heap operations, you don't have the elements in heap order according to the default comparator, so sort_heap isn't guaranteed to work correctly. The regular sort algorithm should work just fine, though.
You need to pass Greater to sort_heap as with all the other heap operations.
sort_heap (v.begin(),v.end(), Greater);
As #Blastfurnace mentions, std::greater<int>() is preferable to defining your own function. Besides the elegance factor, there is a performance issue: when you pass a function by reference for implicit conversion to a functor, it is first implicitly converted to a function pointer, which can result in less efficient execution due to an indirect branch instruction.