Use of std::greater - c++

I am curious about the use of std::greater.
When used with sort, it outputs the numbers in descending order. But when used with priority_queue, numbers are output in ascending order. Why so?
Example:
#include <iostream> // std::cout
#include <functional> // std::greater
#include <algorithm> // std::sort
#include <queue> // std::priority_queue
int main () {
int numbers[]={20,40,50,10,30};
std::priority_queue<int, std::vector<int>, std::greater<int>> pq (numbers, numbers+5);
std::sort(numbers, numbers + 5, std::greater<int>());
while(!pq.empty()){
std:: cout << pq.top() << ' ';
pq.pop();
}
std::cout << '\n';
for (int i=0; i<5; i++)
std::cout << numbers[i] << ' ';
return 0;
}
The output of above code is:
10 20 30 40 50
50 40 30 20 10
Or similar lines,
std::priority_queue<int, std::vector<int>, std::greater<int> > creates a min heap whereas std::priority_queue<int, std::vector<int>, std::less<int> > creates a max heap. Could have been the other way round. Why is it so?

Citing std::priority_queue at cppreference [emphasis mine]
A priority queue is a container adaptor that provides constant time
lookup of the largest (by default) element, at the expense of
logarithmic insertion and extraction.
A user-provided Compare can be supplied to change the ordering, e.g.
using std::greater<T> would cause the smallest element to appear as
the top().
So this order is expected, and does not really relate to how std::sort sorts element based on a supplied binary comparison function.
Sorts the elements in the range [first, last) in ascending
order.
...
Parameters
first, last - the range of elements to sort
policy - the execution policy to use. See execution policy for details.
comp - comparison function object (i.e. an object that satisfies the
requirements of Compare) which returns true if the first argument
is less than (i.e. is ordered before) the second.
As std::greater will return true if its first argument is greater than its second one, we expect the elements to be sorted in descending order when using std::sort with std::greater as function object for performing comparisons.
I.e., std::greater just happens to be the function object used for performing comparisons in these two different contexts of your example.

Related

Fail of Vectors Comparison

I'm trying to compare two vectors , and as what I know vectors support the relational operators and it works in this way: compare the 1st element in v1 with 1st element in v2 and so on ..
why the result of the following code is (true) where the last element in v1 > v2 ?!
#include <iostream>
#include <vector>
using namespace std;
void main()
{
vector <int> V1 = { 2,1,0,3 };
vector <int> V2 = { 3,4,2,2 };
cout << (V1 <= V2); //print true !!
system("pause");
}
operator==,!=,<,<=,>,>= compare the contents of both vectors lexicographicall.
From http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare :
Lexicographical comparison is a operation with the following properties:
Two ranges are compared element by element.
The first mismatching element defines which range is lexicographically less or greater than the other.
This is why a string "abcdx" is less than "abced" and [2,1,0,3] is less than [3,4,2,2].
std::vector is a data container and has nothing to do with the mathematical concecpt of a vector beside containing more than one element.
The doc of std::vector states how the comparison works:
The equality
comparison (operator==) is performed by first comparing sizes, and if
they match, the elements are compared sequentially using operator==,
stopping at the first mismatch (as if using algorithm equal).
The less-than comparison (operator<) behaves as if using algorithm
lexicographical_compare, which compares the elements sequentially
using operator< in a reciprocal manner (i.e., checking both a

Initializing set with comparator in C++

I encountered the following code:
#include <iostream>
#include <set>
int main() {
auto comp = [](int x, int y){return (x > y); };
std::set<int, decltype(comp)> inversed({1,2,3,4,5}, comp);
for ( auto i = inversed.begin(); i != inversed.end(); ++i ) {
std::cout << *i << std::endl;
}
return 0;
}
The code prints "5 4 3 2 1", i.e initial set in inversed order. Can anybody explain why? How comparator influences initialization of the set?
Thanks,
Kostya
An std::set uses a comparator to determine the order of elements. The default semantics for a comparator is "less", which means that if running a comparator on two values (A,B) returns true, then A should be placed before B.
In your case, the comparator does the opposite (returns true if A is "greater" than B), that's why bigger elements appear in front of the smaller ones.
When defining comp, you are defining the order function for your set. For your set, two elements will be ordered if its order function will be fulfilled.
So, being std::set an ordered container, you get that result, i.e. inversed store its elements sorted, but the order is descending because it's the order defined by comp.

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

Is there any library for binary Search in C++

Is there any pre-implemented library in C++ for fast search in a list like binary search? Does the normal list support any kind of find function? Or any function like exists?
I have a list of objects, I want to store them in a list, but not duplicate elements. I want to notice whether or not the new element exists in the list and do a proper action.
There is std::lower_bound() which finds a suitable position in any bidirectional sequence using O(log n) comparisons. Since linked lists don't support random access traversal is O(n). You can use std::binary_search() if you are only interested whether there is a suitable object but this algorithm isn't useful if you are interested in locating the object. Of course, a precondition for std::lower_bound() and std::binary_search() is that the sequence is sorted.
I believe you are looking for the C++ <algorithm> library. It includes a function called binary_search.
An example of it is provided on the page and echoed here:
// binary_search example
#include <iostream> // std::cout
#include <algorithm> // std::binary_search, std::sort
#include <vector> // std::vector
bool myfunction (int i,int j) { return (i<j); }
int main () {
int myints[] = {1,2,3,4,5,4,3,2,1};
std::vector<int> v(myints,myints+9); // 1 2 3 4 5 4 3 2 1
// using default comparison:
std::sort (v.begin(), v.end());
std::cout << "looking for a 3... ";
if (std::binary_search (v.begin(), v.end(), 3))
std::cout << "found!\n"; else std::cout << "not found.\n";
// using myfunction as comp:
std::sort (v.begin(), v.end(), myfunction);
std::cout << "looking for a 6... ";
if (std::binary_search (v.begin(), v.end(), 6, myfunction))
std::cout << "found!\n"; else std::cout << "not found.\n";
return 0;
}
If you are writing real C++ code you can use the algorithm standard library.
In it there is the find function which grant to you to look for a specific element defined between a range of element specified as a parameter.
You can find a real example in the same page.
Container list is not adopted for ordering storing of elements and for their direct access. Though standard class std::list has member functions sort nevertheless the search using bidirectional iterators (std::listhas bidirectional iterators) instead of random access iterators is not very effective..
It would be better if you would use some associative container as for example std::map or std::set (if you need unique elements) or std::multimap or std::multiset (if elements can be duplucated).
if the order of elements is not important then you could use some standard unordered container as std::unordered_map or std::unordered_set

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.