2

C++ inbuilt sort function does not work when we use equals sign in its comparator function with large and repeating input. I have pasted the code here and in validate section if I use equals sign in (val1<=val2) so this does not work for large and repeating inputsbut if i use it without equals sign everything works fine. Can anyone explain why?

I have already tried the code in different compilers as well as different devices.The same problem persists there as well.

#include<bits/stdc++.h>
using namespace std;
bool validate(int val1,int val2)
{
    if(val1<=val2)  
        return true;
    else
        return false;
}
int main()
{
    int total_elements;
    cin>>total_elements;
    vector<int> nums(total_elements);

    for(int i=0;i<total_elements;i++)
      cin>>nums[i];

    sort(nums.begin(),nums.end(),validate);

    for(int i=0;i<total_elements;i++)
      cout<<nums[i]<<" ";


}

Runtime error occurs and the processing stops in the middle but if i use it without equals sign everything works fine.

  • 7
    It is a requirement of the algorithm. – Vlad from Moscow Oct 08 '19 at 17:10
  • 1
    Look for "strict weak ordering" on the web. That's what you need for `std::sort` to work. – R Sahu Oct 08 '19 at 17:14
  • https://stackoverflow.com/questions/979759/operator-and-strict-weak-ordering – R Sahu Oct 08 '19 at 17:15
  • 1
    The `validate` must satisfy that `validate(a,a)==false`. – conditionalMethod Oct 08 '19 at 17:18
  • 1
    Unrelated: Be cautious with `#include` ([Why](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h)) and `using namespace std;` ([Why](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice)). Be very careful when combining the two as they amplify each other's worst effects. If you are doing this for speed during competitions, note that `#include` slows your build times by close to an order of magnitude. After two or three compiles, the time saved on typing is usually eaten up. – user4581301 Oct 08 '19 at 17:20
  • 1
    `if(val1<=val2) return true; else return false;` can be written better/simpler as just `return val1 <= val2;`. – Jesper Juhl Oct 08 '19 at 17:27
  • `#include using namespace std;` - Please, don't *ever* do that. – Jesper Juhl Oct 08 '19 at 17:34

5 Answers5

3

Because the ≤ relation is not a strict weak ordering.

Strict weak ordering is is defined by:

A strict weak ordering is a binary relation < on a set S that is a strict partial order (a transitive relation that is irreflexive, or equivalently,[6] that is asymmetric) in which the relation "neither a < b nor b < a" is transitive.

Note the requirement of irreflexivity.

A binary relation is called irreflexive, or anti-reflexive, if it doesn't relate any element to itself.

It is easy to show that ≤ does not have this property. Consider for example: 0 ≤ 0. Clearly, this number (and also all other integers) is related with itself, so ≤ is not irreflexive (it is reflexive) and therefore is not a strict partial order and therefore it is not a strict weak ordering.

The comparison function of std::sort is required to be a strict weak ording. Using ≤ violates this requirement, and behaviour of using it is undefined.

eerorika
  • 232,697
  • 12
  • 197
  • 326
3

The algorithm requires the function to define a strict weak ordering, otherwise its behaviour is undefined.

This means that,

  • an element is not ordered before itself;
  • if x is ordered before y, y is not ordered before x;
  • if x is ordered before y and y is ordered before z, x is ordered before z.

(These are formally known as irreflexivity, asymmetry, and transitivity.)

Using <= violates both the first points, since

  • x <= x for all x;
  • if x == y then you have both x <= y and y <= x.
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
2

Here is a layman's explanation of why using <= isn't going to work.

I am the sort function that requires a true or false answer to determine if an item comes before the other. I give you two items that happen to be equal, call them item A and item B. I ask you "which comes before the other?" You say "A", because a <= b (you return true).

Then I take the same two equal items, but give them to you first B, then A. You now tell me that "B" comes before A because again, a <= b. Huh? That's ambiguous. You first told me one thing, that A comes before B, and then contradicted yourself by telling me that "B comes before A", and all I did was hand you the same two items, just in a different order.

That's why using <= isn't going to work -- it goes completely wild if the two items are equal.

BTW, the Visual C++ debug runtime does this very same test I described, to determine if your sort criteria follows a strict-weak-order. If VC++ detects this ambiguity, an assertion is raised and you get that scary dialog that you have invalid comparison criteria.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
1

The way the comparator determines if two elements are equal is if neither one is less then the other. In other words, if we have a and b, then if a < b and b < a are both false the values are considered equal.

For simplicity, let's assume we have ints. If the comparator uses <= and a = b = 4, then a <= b and b <= a are both true.

You can read more details on the requirements on cppreference.

super
  • 12,335
  • 2
  • 19
  • 29
0

Sort requires strict weak ordering to work:

Almost all stl containers rely on strict weak ordering. A strict weak ordering defines the relative position of elements in terms of precedence of one item over other. For eg. if you have a room full of person and you have to form a queue based on their height, a person with "lesser" height will "precede" the person with greater height. For a function to be satisfying strict weak ordering following conditions need to be met:

a < b => !(b < a) 
!(a < b) && !(b < a) => a≡b
Oblivion
  • 7,176
  • 2
  • 14
  • 33