issue relational operator in vector c++ - c++

today I wrote this code
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector <int> a (4,100);
vector <int> b (1,100);
cout<<(b<a);
}
as the reference says this is true only if if the contents of the b are lexicographically less than the contents of a, false otherwise, but in the output I obtain true, someone can explain me.
http://en.cppreference.com/w/cpp/container/vector/operator_cmp

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.
. If one range is a prefix of another, the shorter range is lexicographically less than the other.
. If two ranges have equivalent elements and are of the same length, then the ranges are lexicographically equal.
. An empty range is lexicographically less than any non-empty range.
. Two empty ranges are lexicographically equal.
In your case, the third clause applies.

The rules for std::lexicographical_compare which is invoked to handle
a < b
say that if one range is a prefix of another, the shorter range is lexicographically less than the other.
Here the range of a refers to the elements from a.begin() up to but excluding a.end() - in other words all the elements in a
Similarly, the range of b refers to the elements from b.begin() up to but excluding b.end() - in other words all the elements in b
b (which holds a single int of value 100) IS a prefix of a (which holds 4 integers of value 100) so b (the shorter range) is considered less than a, hence b < a is true.
See http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare for further details.

Related

How to understand the requirement of `std::lower_bound`?

As per the document about std::lower_bound, which says that:
The range [first, last) must be partitioned with respect to the expression element < value or comp(element, value), i.e., all elements for which the expression is true must precede all elements for which the expression is false. A fully-sorted range meets this criterion.
I have a little difficulty to fully understand it.
1.What's element < value? It seems that element (or value) is never mentioned before this paragraph in the aforementioned document. Does the said element mean the elements before the current element, and the said value means the value of the current element?
UPDATED:
2.Since whether a specific sequence is valid(i.e. suits the requirement) or not depends the value, the requirement for a specific sequence could not be always be guaranteed when the value is different. I think it's meaningless to define such a requirement. It's seems that a fully sorted seuqence is more reliable and practical.
What's element < value
value is the parameter to lower_bound, see at the beginning of that page:
template< class ForwardIt, class T > ForwardIt lower_bound( ForwardIt
first, ForwardIt last, const T& value );
The value in question is mentioned right here, the last parameter to the template. And element, references to some element and every element in the sequence.
This is rather a terse way to define the following: take every element in the sequence, one element at a time. When you do that, all elements for which the expression element < value returns true must appear in the sequence before all other elements, for which the same expression is false. It is explicitly intentional for the requirements to be defined in this manner, here's the explanation:
For example, if value is 4, and we're talking about natural integers, here's one such sequence:
1, 2, 3, 4, 5, 6
Here, all the elements for which this expression is true (1, 2, and 3), appear before all the elements for which this expression is false (4, 5, and 6).
The following sequence is also a valid sequence, in this case:
3, 2, 1, 6, 5, 4
Here, same thing: 3, 2, and 1, for which the expression element < 4 is true, appears before value 4, 5 and 6 for which the expression element < 4 would be false. So, yes, this would also be a valid sequence for a call to lower_bound for the value of 4.
The following sequence will NOT be a valid sequence for this specific case of using std::lower_bound:
1, 2, 4, 3, 5, 6
And as far as why is this lower_bound requirement specified in such an strange manner, well, that would be a different question. But this is what it means.
From cppreference
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.
The range [first, last) must be partitioned with respect to the
expression element < value or comp(element, value), i.e., all elements
for which the expression is true must precede all elements for which
the expression is false. A fully-sorted range meets this criterion.
From your question:
What's element < value? It seems that element (or value) is never
mentioned before this paragraph in the aforementioned document. Does
the said element mean the elements before the current element, and the
said value means the value of the current element?
value and comp are mentioned in the function signatures at the beginning of the page. value is the argument with which you call std::lower_bound, and comp an optional comparison function; shouldn't a comparison function be provided, < would be used instead.
element refers to each element in the range [first, last).
So, what std::lower_bound does is to compare value to the elements in the range until it finds the first one that is not "less than" (through < or comp) value.
The requirement for std::lower_bound to work is that the input range is partitioned in such a way that all the elements that are "less than" value are placed before the rest; that requirement is met, for example, if the range is fully sorted.
(As #Passerby mentions in the comments below, std::lower_bound won't need to compare against all the elements that are "less than" value, due to the partitioned range requirement, but that is an implementation detail.)
Partitions
A list of values may be partitioned, or grouped according to some criterion. For example:
┌────┬────┬────┬────┬────┬────┬────┬────┐
| 2 | 7 | 3 | -5 | 11 | 94 | 15 | 12 |
└────┴────┴────┴────┴────┴────┴────┴────┘
x < 10 | x ≥ 10
In this list we have two partitions:
elements where x < 10
elements where x is not < 10
Further, the criterion implies an order:
all xs such that (x < 10) come —before— all xs such that !(x < 10)
(In C++ we tend to use a “comparator” or “comparison function” to specify the criterion.)
Notice that it does not matter what order the elements are relative to each other in each partition! That said, it is also noteworthy that if the list were sorted, it would still have the exact same two partitions:
┌────┬────┬────┬────┬────┬────┬────┬────┐
| -5 | 2 | 3 | 7 | 11 | 12 | 15 | 94 |
└────┴────┴────┴────┴────┴────┴────┴────┘
x < 10 | x ≥ 10
(My example here has two equal-sized partitions. That is not necessarily the case. A partition may have zero or more elements, and each partition may have a different size than the others.)
Lower bound → index of start of partition
What the lower_bound algorithm does is find the first element of an existing partition.
The only caveat that the algorithm requires is that the sequence must already be partitioned in a way that the sort criterion makes sense. (Because the algorithm only finds partitions, it does not sort stuff!)
For example, our original sequence does not support a criterion that separates elements into (x < 7) and (x ≥ 7), because the elements are not partitioned in that way — it would not make sense to try to find the “first” element of a partition that doesn’t exist.
This is the meaning of the language used by cppreference.com.

Will std::sort always compare equal values?

I am doing the following problem on leetcode: https://leetcode.com/problems/contains-duplicate/
Given an integer array nums, return true if any value appears at least
twice in the array, and return false if every element is distinct.
The solution I came up to the problem is the following:
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
try {
std::sort(nums.begin(), nums.end(), [](int a, int b) {
if (a == b) {
throw std::runtime_error("found duplicate");
}
return a < b;
});
} catch (const std::runtime_error& e) {
return true;
}
return false;
}
};
It was accepted on leetcode but I am still not sure if it will always work. The idea is to start sorting nums array and interrupt as soon as duplicate values are found inside comparator. Sorting algorithm can compare elements in many ways. I expect that equal elements will be always compared but I am not sure about this. Will std::sort always compare equal values or sometimes it can skip comparing them and therefore duplicate values will not be found?
Will std::sort always compare equal values or sometimes it can skip comparing them and therefore duplicate values will not be found?
Yes, some equal value elements will always be compared if duplicates do exist.
Let us assume the opposite: initial array of elements {e} for sorting contains a subset of elements having the same value and a valid sorting algorithm does not call comparison operator < for any pair of the elements from the subset.
Then we construct same sized array of tuples {e,k}, with the first tuple value from the initial array and arbitrary selected second tuple value k, and apply the same sorting algorithm using the lexicographic comparison operator for the tuples. The order of tuples after sorting can deviate from the order of sorted elements {e} only for same value elements, where in the case of array of tuples it will depend on second tuple value k.
Since we assumed that the sorting algorithm does not compare any pair of same value elements, then it will not compare the tuples with the same first tuple value, so the algorithm will be unable to sort them properly. This contradicts our assumptions and proves that some equal value elements (if they exist in the array) will always be compared during sorting.

How does s.compare member function behave in the C++ code below?

I have this C++ code below to solve for a homework and after I ran it with Code::Blocks, it tells me that i=0, which means the expression s.compare(t)<0 is false. But, the way I see it, it's the other way around: (s<t, because AbcA < AAbcA). Can someone please explain it to me?
#include <iostream>
#include <string>
using namespace std;
int main(void) {
string s = "Abc", t = "A";
s=s+t;
t=t+s;
int i = s.compare(t)<0;
int j = s.length()<t.length();
cout<<i+j<<endl;
return 0;
}
According to the reference std::string::compare returns:
negative value if *this appears before the character sequence specified by the arguments, in lexicographical order
zero if both character sequences compare equivalent
positive value if *this appears after the character sequence specified by the arguments, in lexicographical order
Lexicographical comparison being defined as:
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.
If one range is a prefix of another, the shorter range is lexicographically less than the other.
If two ranges have equivalent elements and are of the same length, then the ranges are lexicographically equal.
An empty range is lexicographically less than any non-empty range.
Two empty ranges are lexicographically equal.
"AbcA" comes lexicographically after "AAbc", because the first nonequal character 'b' (ASCII 0x62) comes after 'A' (ASCII 0x41)

[C++][std::sort] How does it work on 2D containers?

I have this vector object that contains vector of ints
std::vector<std::vector<int>> vec;
I have been trying to figure out how std::sort(vec.begin(), vec.end()) works on it. Here are my observations:
2D vectors are sorted by size.
If some of inner vectors has the same size, the vector with lesser value of first element will have lesser index value.
I have been generating a few 2D vectors now, and it seems that these two are always true. However, I am doubting about my second assumption. Does std::sort really work this way, or it was just some luck that made my assumptions correct?
Sorting vector elements works the same way as sorting any other type. std::sort uses the comparison object given as an argument. If none was passed explicitly, std::less is the default.
std::less uses operator<. As per vector documentation, it:
Compares the contents of lhs and rhs lexicographically. The comparison is performed by a function equivalent to std::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.
If one range is a prefix of another, the shorter range is lexicographically less than the other.
If two ranges have equivalent elements and are of the same length, then the ranges are lexicographically equal.
An empty range is lexicographically less than any non-empty range.
Two empty ranges are lexicographically equal.
In short, lexicographical sorting is the same as sorting used for dictionaries (ignoring oddities of some languages).
2D vectors are sorted by size.
Not quite. {1}, {3, 4}, {1, 2, 5} would be sorted as {1}, {1, 2, 5}, {3, 4}.
std::sort uses operator < by default to sort. Since std::vector has an overloaded operator < it uses that. std::vector::operator < does a lexicographical compare meaning it returns the vector that has the first smaller element. That means {1, 1, 2} is less than {1, 1, 3} since the 2 is less than 3. If the vectors are of different length but the smaller one has the same elements that the larger one has then the smaller one is returned. That means that
int main()
{
std::vector a{5, 1}, b{10};
std::cout << (a < b);
}
Prints 1 since 5 is less than 10.
int main()
{
std::vector a{5, 10}, b{5};
std::cout << (a < b);
}
Prints 0 since a is larger than b but they have the same common element.

What's the logic behind the order the elements are passed to a comparison function in std::sort?

I'm practicing lambdas:
int main()
{
std::vector<int> v {1,2,3,4};
int count = 0;
sort(v.begin(), v.end(), [](const int& a, const int& b) -> bool
{
return a > b;
});
}
This is just code from GeeksForGeeks to sort in descending order, nothing special. I added some print statements (but took them out for this post) to see what was going on inside the lambda. They print the entire vector, and the a and b values:
1 2 3 4
a=2 b=1
2 1 3 4
a=3 b=2
3 2 1 4
a=4 b=3
4 3 2 1 <- final
So my more detailed question is:
What's the logic behind the order the vector elements are being passed into the a and b parameters?
Is b permanently at index 0 while a is iterating? And if so, isn't it a bit odd that the second param passed to the lambda stays at the first element? Is it compiler-specific? Thanks!
By passing a predicate to std::sort(), you are specifying your sorting criterion. The predicate must return true if the first parameter (i.e., a) precedes the second one (i.e., b), for the sorting criterion you are specifying.
Therefore, for your predicate:
return a > b;
If a is greater than b, then a will precede b.
So my more detailed question is: What's the logic behind the order the vector elements are being passed into the a and b parameters?
a and b are just pairs of elements of the elements you are passing to std::sort(). The "logic" will depend on the underlying algorithm that std::sort() implements. The pairs may also differ for calls with identical input due to randomization.
Is 'b' permanently at index 0 while 'a' is iterating? And if so, isn't it a bit odd that the second param passed to the lambda stays at the first element?
No, because the first element is the higher.
Seems that, with this algorithm, all elements are checked (and maybe switched) with the higher one (at first round) and the higher one is placed in first position; so b ever points to the higher one.
For Visual Studio, std::sort uses insertion sort if the sub-array size is <= 32 elements. For a larger sub-array, it uses intro sort, which is quick sort unless the "recursion" depth gets too deep, in which case it switches to heap sort. The output you program produces appears to correspond to some variation of insertion sort. Since the compare function is "less than", and since insertion sort is looking for out of order due to left values "greater than" right values, the input parameters are swapped.
You just compare two elements, with a given ordering. This means that if the order is a and then b, then the lambda must return true.
The fact that a or b are the first or the last element of the array, or fixed, depends on the sorting algorithm and of course of your data!