std::vector and std::min behavior - c++

Why following program is not returning minimum value as 1.
#include <vector>
#include <algorithm>
#include <iostream>
int main ( int argc, char **argv) {
std::vector<int> test;
test.push_back(INT_MAX);
test.push_back(1);
int min = *(std::min(test.begin(), test.end()));
std::cout << "Minimum = " << min << std::endl;
}
It returns minimum values as 2147483647

You could try this:
int min = *std::min_element(test.begin(), test.end());
std::min
Return the lesser of two arguments
Returns the lesser of a and b. If both are equivalent, a is returned.
std::min_element
Returns an iterator pointing to the element with the smallest value in the range [first,last). The comparisons are performed using either operator< for the first version, or comp for the second; An element is the smallest if no other element compares less than it (it may compare equal, though).

Be aware that std::vector<T>::end() does NOT give you an iterator to the last element. It returns an iterator pointing BEHIND the last element.
If you want to address the first and last element with iterator logic you need to use (test.begin(), test.end()-1).

Related

std::map find distance with iterators, program does not terminate

As I compile ( g++ -std=c++14 map.cpp ) and run this program, it doesn't seem to terminate. Can any one explain Why? However as I do find('a') instead of 'c' it gives a zero.
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
map<char, float> m;
m['a'] = 3.4;
m['b'] = 5.3;
m['c'] = 33.3;
m['d'] = 43.;
auto it = m.find( 'c' );
cout << "distance : " << std::distance( it , m.begin() ) << endl;
}
Use
std::distance( m.begin(), it )
Otherwise the call
std::distance( it , m.begin() )
has undefined behavior because there is used an invalid range. Ranges in C++ are specified like [first, last ) where first precedes or equal to last. In the last case when first is equal to last the range is empty.
From the C++ Standard (27.4.3 Iterator operations)
4 Effects: If InputIterator meets the requirements of random access
iterator, returns (last - first); otherwise, returns the number of
increments needed to get from first to last.
std::distance(first,last) starts running from first and advances the iterator until it reaches the last. In your case this will never happen because it is most likely found after m.begin() so it'll loop forever. change the order of parameters given to std::distance
std::distance reference:
The behavior is undefined if last is not reachable from first by
(possibly repeatedly) incrementing first.

Why does std::distance() for std:list<int>::iterator not return a negative number when last is before first?

std::distance is giving me a circular distance on std::list, not a relative distance. Why?
#include <list>
#include <iostream>
#include <iterator>
using namespace std;
int main(){
list<int> derp = {1,2,3,4};
auto begin = derp.begin();
auto end = derp.end();
end--;
cout << distance(end, begin) << endl;
cout << distance(begin, end) << endl;
}
When I run this, the following output happens:
2
3
I expect the following:
-3
3
Why is this happening?
Your code has undefined behavior. For std::distance
If InputIt is not LegacyRandomAccessIterator, the behavior is undefined if last is not reachable from first by (possibly repeatedly) incrementing first. If InputIt is LegacyRandomAccessIterator, the behavior is undefined if last is not reachable from first and first is not reachable from last.
The iterator of std::list is not RandomAccessIterator, and its begin is not reachable from end by incrementing end.
For iterators that do not meet the requirements of a random access iterator, std::distance returns the number of times first (the first argument) must be incremented to equal last (the second argument).
You are using a std::list, which does not have random access iterators. In the case of distance(end, begin), no matter how many times you increment end, it will never equal begin. Thus, the behaviour is undefined, and the result depends on the particulars of your standard library implementation.

Iterator confusion using maps

sorry because this question isn't really advanced, but I am having lots of trouble understanding why this program works the way it does.
#include <iostream>
#include <fstream>
#include <set>
#include <vector>
#include <map>
using namespace std;
int main() {
ofstream fout("castle.out");
ifstream fin("castle.in");
map<int, int, greater<int> > cnt;
map<int, int, greater<int> >::iterator x;
x = cnt.begin();
cnt[1] = 0;
cnt[2] = 7;
fout << x->first; //This outputs 2
x++;
fout << x->second;//This outputs 2 again, why not 0?
return 0;
}
So I defined a map called cnt, and then made an iterator for it x. I ordered it by greatest integer to least greatest integer. I set that iterator equal to x.begin(), and then I outputted the value of x, using first. But then I wanted to output the value 0, so I did one x++; and then tried to output the value of x->first. The idea behind this was that the iterator would increase by one and point to the next pair in my map, so then it would point to 1, which comes after the 2.
Why does it not work and give me 2 again?
I realized that if I do this instead:
x++;
x++:
fout << x-> first;
with two x++, I will have the value 1. Why is this? Thanks!
Your code has undefined behavior.
x = cnt.begin();
Sets x to begin() while the container is empty which effectively gives you the end() iterator. Since std::map::operartor[] doesn't invalidate any iterators you still have an end() iterator and dereferencing it is undefined behavior.

How to get max_element from vector<std::string>

Using the code from cplusplus.com, I am trying to find the max int value in an vector<std::string>.
the vector is in std::string format and there is no choice here.
bool myfn(int i, int j)
{
return i < j;
}
vector<std::string> dat;
dat.push_back(2.1);
dat.push_back(5.3);
for (int l = 0; l < dat.size(); ++l)
{
std::cout << *std::max_element(dat.begin(), dat.end(), myfn) << '\n';
}
expected output:
3
error:
.cpp:76:93: error: no matching function for call to 'max_element(std::vector<std::basic_string<char> >&, std::vector<std::basic_string<char> >::size_type, bool (&)(int, int))'
How do you find the max value in a vector<std::string>?
You're calling max_element with the wrong arguments. It takes two iterators and a function:
template <class ForwardIterator, class Compare>
ForwardIterator max_element (ForwardIterator first, ForwardIterator last,
Compare comp);
You're calling it with a vector and a size. The confusion might stem from the example on the reference you link where they do:
std::min_element(myints, myints +7, myfn)
// ^^^^^^ ^^^^^^^^^
// int* int*
In this case, both myints and myints + 7 are of type int*, and a raw pointer is an iterator. In your case however, you are passing two different types (vector<string> and size_t), neither of which is an iterator. So you need to instead do:
*std::max_element(dat.begin(), dat.end(), myfn)
Or, to illustrate something equivalent to the example in the reference (although definitely prefer the above):
std::string* first = &dat[0];
*std::max_element(first, first + dat.size(), myfn)
Which works because in this case I am passing two string*'s, which are iterators.
(Also based on your usage, dat should be vector<int> not vector<string>.)
You have a vector that is full of strings vector<std::string> dat; but yet your comparison functions takes 2 integers. You might want to either change the type that is stored in the vector or change the comparison function you use. If you use integers then the default comparison operator will do what you want already without you needing to write a custom function.
Also std::max_element expects to get iterators one for the start and one for the end, so you need to change your call to be something like std::max_element(dat.begin(), dat.end(), myfn). You might notice that the loop you have is actually not needed because you already go over that range with the call to std::max_element all this loop does is compute the exact same value multiple times, you only need to compute it once.
Your std::vector dat declaration is wrong as you want to push_back int.
std::max_element and std::min_element returns an iterator not value. You can have a look into the following example
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<int> v {1,2,3,4,6};
auto biggest = std::max_element(std::begin(v), std::end(v));
std::cout << "Max element is " << *biggest
<< " at position " << std::distance(std::begin(v), biggest) << std::endl;
auto smallest = std::min_element(std::begin(v), std::end(v));
std::cout << "min element is " << *smallest
<< " at position " << std::distance(std::begin(v), smallest) << std::endl;
return 0;
}
Pointers can be iterators. This is what allows you to use arrays as a range in standard library functions. myints is an expression that refers to the first element of the array, and myints + 7 refers to one past the end of the array. Equivalently you can do std::begin(myints) and std::end(myints). Standard containers expose iterators in the form of these member functions myvector.begin() and myvector.end(). You pass these iterators, not the container and size, to std::max_element.
By default, std::max_element uses operator< to compare the elements. You don't need a comparator functor in this instance.
Your std::vector's value_type is std::string, but you're trying to pass an int. Either change the value_type to int, or use a string conversion function, i.e. C++11's std::to_string.
Finally, your loop is completely unnecessary. std::max_element operators over a range.
std::vector<int> dat;
dat.push_back(1);
dat.push_back(3);
std::cout << *std::max_element(dat.begin(), dat.end()) << '\n';

binary_search in c++ unexpected behaviour

The following snippet is returning me 0. I expected it to be 1. What's wrong going on here?
#include <iostream>
#include <iterator>
#include <ostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(){
vector<int> v;
int arr[] = {10,20,30,40,50};
v.push_back(11);
v.push_back(22);
copy(arr,arr + sizeof(arr)/sizeof(arr[0]),back_inserter(v)); // back_inserter makes space starting from the end of vector v
for(auto i = v.begin(); i != v.end(); ++i){
cout << *i << endl;
}
cout << endl << "Binary Search - " << binary_search(v.begin(), v.end(), 10) <<endl; // returns bool
}
I am using gcc /usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper
I ran the program and saw this:
11
22
10
20
30
40
50
Binary Search - 0
Your array is not sorted, therefore, binary search fails. (it sees 11 in the first position, and concludes 10 does not exist here)
You either want to ensure the array is sorted before binary searching or use the regular std::find.
binary_search says:
Checks if the sorted range [first, last) contains an element equal to
value. The first version uses operator< to compare the elements, the
second version uses the given comparison function comp.
Your list is not sorted, it contains the elements 11 and 22 prior to 10.
Your array is not sorted, so binary_search got undefined behavior. Try std::find instead
bool found = std::find(v.begin(), v.end(), 10) != v.end()
ยง25.4.3.4 of the C++11 standard (3242 draft)
Requires: The elements e of [first,last) are partitioned with respect to the expressions e < value and !(value < e) or comp(e,
value) and !comp(value, e). Also, for all elements e of [first, last),
e < value implies !(value < e) or comp(e, value) implies !comp(value,
e).
"Unexpected behavior"? There's nothing unexpected here.
The whole idea of binary search algorithm is taking advantage of the fact that the input array is sorted. If the array is not sorted, there can't be any binary search on it.
When you use std::binary_search (as well as all other standard binary search-based algorithms), the input sequence must be sorted in accordance with the same comparison predicate as the one used by std::binary_search. Since you did not pass any custom predicate to std::binary_search, it will use the ordering defined by < operator. That means that your input Sequence of integers must be sorted in ascending order.
In your case the input sequence does not satisfy that requirement. std::binary_search cannot be used on it.