Search code examples
c++sortingcomparator

what is the difference between "return num1<num2" and "return num2-num1" in comparator


I am learning how to write the comparator in C++. At first time, I return num1<num2, as a result I get a set in ascending order. Then I return num1>num2 and I get a set in descending order. Now I try to return num1-num2 which should equal to num1>num2 in my opinion, I get a set in descending order as predicted. But when I try to return num2-num1, I still get a set in descending order. How could it happen? Is there any difference between return num2-num1 and return num1<num2?

    #include <iostream>
    #include <set>
    using namespace std;
    
    struct myCmp{
        bool operator()(const int& num1, const int& num2){
            return num2-num1;
        }
    };

int main()
{   
   set<int,myCmp> st;
   st.insert(1);
   st.insert(2);
   st.insert(3);
   for(auto it=st.begin();it!=st.end();it++){
       cout<<*it<<endl;
   }
   return 0;
}

Solution

  • Now I try to return num1-num2 which should equal to num1>num2 in my opinion

    That is incorrect.

    Is there any difference between return num2-num1 and return num1<num2?

    Yes.

    num2-num1 returns an integer value that is the result of subtracting the value of num1 from the value of num2. Since your comparator returns a bool, a result of 0 will be converted to false, and any other result will be converted to true.

    num1<num2 returns a boolean value specifying whether or not num1 is actually less-than num2. Any value of num1 that is less-than the value of num2 will return true, all other values will return false.

    So, as you can see, both approaches return completely different things.

    std::set has the following requirement:

    std::set is an associative container that contains a sorted set of unique objects of type Key. Sorting is done using the key comparison function Compare. Search, removal, and insertion operations have logarithmic complexity. Sets are usually implemented as red-black trees.

    Everywhere the standard library uses the Compare requirements, uniqueness is determined by using the equivalence relation. In imprecise terms, two objects a and b are considered equivalent if neither compares less than the other: !comp(a, b) && !comp(b, a).

    Using return num1<num2 (or return num1>num2) satisfies that requirement, but return num2-num1 breaks it.

    For example, let's assume a = 1 and b = 2.

    Using num1<num2, you get the following:

      !comp(a, b) && !comp(b, a)
    = !comp(1, 2) && !comp(2, 1)
    = !(1 < 2) && !(2 < 1)
    = !true && !false
    = false && true
    = one is less-than the other, so not equal, which is correct!
    

    Using num1>num2, you get the following:

      !comp(a, b) && !comp(b, a)
    = !comp(1, 2) && !comp(2, 1)
    = !(1 > 2) && !(2 > 1)
    = !false && !true
    = true && false
    = one is less-than the other, so not equal, which is correct!
    

    Using num2-num1, you get the following:

      !comp(a, b) && !comp(b, a)
    = !comp(1, 2) && !comp(2, 1)
    = !(2 - 1) && !(1 - 2)
    = !(1) && !(-1)
    = !true && !true
    = false && false
    = neither is less-than the other, so equal, which is incorrect!