unexpected output from C++ multiset lower_bound - c++

Wondeirng why below code returns 1? I never insert 1 into the multiset container.
#include <iostream>
#include <set>
int main ()
{
std::multiset<int> mymultiset;
std::multiset<int>::iterator itlow;
mymultiset.insert(-3);
itlow = mymultiset.lower_bound (3);
std::cout << *itlow << endl; // output 1
return 0;
}

mymultiset.lower_bound(3) returns the lowest location in the container where 3 could go, and that's at the end of the container. So itlow is equal to mymultiset.end(), and it is not dereferenceable. std::cout << *itlow has undefined behavior.

You are trying to get an Iterator which his lower bound is 3, and your maximum value is -3. So you've got an end iterator, which his value is undefined.
You should use multiset::begin() as your Iterator, or put something like itlow = mymultiset.lower_bound (-4); which is not very gentle.

Hi to clarify my understanding
I have one multiset which contains 1 and 5.
mset.insert(1);
mset.insert(5);
auto it = s.lower_bound(6);
cout<<*it<<endl;
Now, from the above answer, I will be getting 2 since that is the location where the value 6 can fit inside the container. Am I right?
Next, if I search for the value 4, I am getting 5.
Here I don't think the iterator has reached the mset.end().
Am I right?
Thanks

Related

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';

Set_Intersection with repeated values

I think the set_intersection STL function described here: http://www.cplusplus.com/reference/algorithm/set_intersection/
is not really a set intersection in the mathematical sense. Suppose that the examples given I change the lines:
int first[] = {5,10,15,20,20,25};
int second[] = {50,40,30,20,10,20};
I would like to get 10 20 20 as a result. But I only get unique answers.
Is there a true set intersection in STL?
I know it's possible with a combination of merges and set_differences, btw. Just checking if I'm missing something obvious.
I would like to get 10 20 20 as a result. But I only get unique answers. Is there a true set intersection in STL?
std::set_intersection works how you want.
You probably get the wrong answer because you didn't update the code properly. If you change the sets to have 6 elements you need to update the lines that sort them:
std::sort (first,first+5); // should be first+6
std::sort (second,second+5); // should be second+6
And also change the call to set_intersection to use first+6 and second+6. Otherwise you only sort the first 5 elements of each set, and only get the intersection of the first 5 elements.
Obviously if you don't include the repeated value in the input, it won't be in the output. If you change the code correctly to include all the input values it will work as you want (live example).
cplusplus.com is not a good reference, if you look at http://en.cppreference.com/w/cpp/algorithm/set_intersection you will see it clearly states the behaviour for repeated elements:
If some element is found m times in [first1, last1) and n times in [first2, last2), the first std::min(m, n) elements will be copied from the first range to the destination range.
Even the example at cplusplus.com is bad, it would be simpler, and harder to introduce your bug, if it was written in idiomatic modern C++:
#include <iostream> // std::cout
#include <algorithm> // std::set_intersection, std::sort
#include <vector> // std::vector
int main () {
int first[] = {5,10,15,20,20,25};
int second[] = {50,40,30,20,10,20};
std::sort(std::begin(first), std::end(first));
std::sort(std::begin(second), std::end(second));
std::vector<int> v;
std::set_intersection(std::begin(first), std::end(first),
std::begin(second), std::end(second),
std::back_inserter(v));
std::cout << "The intersection has " << v.size() << " elements:\n";
for (auto i : v)
std::cout << ' ' << i;
std::cout << '\n';
}
This automatically handles the right number of elements, without ever having to explicitly say 5 or 6 or any other magic number, and without having to create initial elements in the output vector and then resize it to remove them again.
set_intersection requires both ranges to be sorted. In the data you've given, second is not sorted.
If you sort it first, you should get your expected answer.

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

Segmentation fault trying to dereference an iterator

I'm trying to find the maximum value of a vector using std::max_element. When I run the program I get a segmentation fault that I believe is to do with std::end going over the end of the vector? I've tried changing it to std::end(tempdata)-1) but to no avail.
auto max = std::max_element(std::begin(tempdata), std::end(tempdata));
std::ofstream maxcurrent("maxcurrent.txt", std::ios::app);
maxcurrent << v << std::setw(15) << *max << std::endl;
Having looked at this answer I don't see why mine isn't working.
It won't work when max is std::end(tempdata) which can occurs if your tempdata is empty.
Iterator to the greatest element in the range [first, last). If several elements in the range are equivalent to the greatest element, returns the iterator to the first such element. Returns last if the range is empty.
source

std::list - Sort one item

Is it possible to sort a list based off one item?
For instance, if I have
1,3,2,4,5,6,7 ... 1000000
And I know that 3 is the second element, is it possible to efficiently sort 3 into it's correct position between 2 and 4 without re-sorting the entire list?
EDIT: I should also note that, in this scenario, it is assumed that the rest of the list is already sorted; it is simply the 3 that is now out of place.
You could simply find that unordered object (O(n)), take the object out (O(1)), find the correct position (O(n)), then insert it again (O(1)).
Assuming C++11,
#include <list>
#include <algorithm>
#include <iostream>
int main() {
std::list<int> values {1, 2, 3, 9, 4, 5, 6, 7, 12, 14};
auto it = std::is_sorted_until(values.begin(), values.end());
auto val = *--it;
// ^ find that object.
auto next = values.erase(it);
// ^ remove it.
auto ins = std::lower_bound(next, values.end(), val);
// ^ find where to put it back.
values.insert(ins, val);
// ^ insert it.
for (auto value : values) {
std::cout << value << std::endl;
}
}
Before C++11 you need to implement std::is_sorted_until yourself.
For this very limited case, writing your own bubblesort would probably be faster than std::sort.
If you have that level of knowledge, why don't you just swap the items yourself rather than trying to coerce sort to do it for you?
Surely that's a better way.
Even if you don't know where it has to go, you can find that out quickly, remove it, then insert it at the correct location.
I suppose you could use the insert method to move the element, but I'd like to know more about the way you calculate its "correct" position: there could be a better suited algorithm.
If you think about the traversal possible for a list, it's clearly only end-to-end. So:
if you don't know where the mis-ordered element is you have to first scan through the elements one by one until you find it, then
you can remember the value and delete the out-of-order element from the list, then
there are two possibilities:
that element is greater in your sorting order than any other element you've yet encountered, in which case you need to keep going through the remaining elements until you find the correct place to insert it.
the element would belong somewhere amongst the elements you've already passed over, in which case:
you can move backwards, or forwards from the first element again, until you find the correct place to put it.
if you've created some records from your earlier traversal you can instead use it to find the insertion place faster, for example: if you've created a vector of list iterators, you can do a binary search in the vector. Vectors of every Nth element, hash tables etc. are all other possibilities.
This is If you dont use std::list.
With a Selection sort algorthm, you simply sort items 0 to 3 ( selectionSort(list,3)) if you know that thats the range.
Not the entire range till the end.
Sample code :
#include <iostream>
using namespace std;
void selectionSort(int *array,int length)//selection sort function
{
int i,j,min,minat;
for(i=0;i<(length-1);i++)
{
minat=i;
min=array[i];
for(j=i+1;j<(length);j++) //select the min of the rest of array
{
if(min>array[j]) //ascending order for descending reverse
{
minat=j; //the position of the min element
min=array[j];
}
}
int temp=array[i] ;
array[i]=array[minat]; //swap
array[minat]=temp;
}
}
void printElements(int *array,int length) //print array elements
{
int i=0;
for(i=0;i<length;i++) cout<<array[i]<<" ";
cout<<" \n ";
}
int main(void)
{
int list[]={1,3,2,4,5,6}; // array to sort
int number_of_elements=6;
cout<<" \nBefore selectionSort\n";
printElements(list,number_of_elements);
selectionSort(list,3);
cout<<" \nAfter selectionSort\n";
printElements(list,number_of_elements);
cout<<" \nPress any key to continue\n";
cin.ignore();
cin.get();
return 0;
}
Output:
Before selectionSort
1 3 2 4 5 6
After selectionSort
1 2 3 4 5 6
Press any key to continue