Fail of Vectors Comparison - c++

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

Related

How to find unique values in a vector c++

I am trying to solve a coding problem where I am to check and see if a vector has unique values and if it does then return true else false.
So Far I thought of using a nested loops where you would compare the first to the last, but I am wanted to know if C++ has anything else then doing a o(n^2) type iteration. I saw that c++ has a unique function, but that would delete the unique value.
Example 1:
Input: nums = [1,2,3,1]
Output: true
Example 2:
Input: nums = [1,2,3,4]
Output: false
std::unique checks for consecutive duplicates and moves them to the end of the range. It does not remove them from the vector. Anyhow you can make a copy. It also returns an iterator to the end of the range of unique values (that are now in the front of the vector):
#include <iostream>
#include <vector>
#include <algorithm>
bool only_unique(std::vector<int> v) {
std::sort(v.begin(),v.end());
return std::unique(v.begin(),v.end()) == v.end();
}
int main(){
std::cout << only_unique({1,2,3,1});
std::cout << only_unique({1,2,3,4});
}
If you don't want to use the additional memory you can change the argument to a reference. Currently, only_unique leaves the parameter unmodified. Even if the vector is passed by reference the duplicates will still be present (just at a different position). This has O(n log n) complexity.
you need to create "set" structure,
it makes it possible to insert values from vector and does not insert the duplicates,
so you can check if the size of the set and the vector match or not.
set<int> st;
for (auto i : nums)
st.insert(i);
return st.size() == nums.size();

Use of std::greater

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.

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.

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.

stdext::hash_map unclear hash function

#include <iostream>
#include <hash_map>
using namespace stdext;
using namespace std;
class CompareStdString
{
public:
bool operator ()(const string & str1, const string & str2) const
{
return str1.compare(str2) < 0;
}
};
int main()
{
hash_map<string, int, hash_compare<string, CompareStdString> > Map;
Map.insert(make_pair("one", 1));
Map.insert(make_pair("two", 2));
Map.insert(make_pair("three", 3));
Map.insert(make_pair("four", 4));
Map.insert(make_pair("five", 5));
hash_map<string, int, hash_compare<string, CompareStdString> > :: iterator i;
for (i = Map.begin(); i != Map.end(); ++i)
{
i -> first; // they are ordered as three, five, two, four, one
}
return 0;
}
I want to use hash_map to keep std::string as a key. But when i insert the next pair order is confused. Why order is do not match to insert order ? how should i get the order one two three four five ??
Why order is do not match to insert order?
That's because a stdext::hash_map (and the platform-independent standard library version std::unordered_map from C++11) doesn't maintain/guarantee any reasonable order of its elements, not even insertion order. That's because it is a hashed container, with the individual elements' position based on their hash value and the size of the container. So you won't be able to maintain a reasonable order for your data with such a container.
What you can use to keep your elements in a guaranteed order is a good old std::map. But this also doesn't order elements by insertion order, but by the order induced by the comparison predicate (which can be confugured to respect insertion time, but that would be quite unintuitive and not that easy at all).
For anything else you won't get around rolling your own (or search for other libraries, don't know if boost has something like that). For example add all elements to a linear std::vector/std::list for insertion order iteration and maintain an additional std::(unordered_)map pointing into that vector/list for O(1)/O(log n) retrieval if neccessary.