Practical summary of C + + sort() function

Posted by Dimwhit on Mon, 10 Jan 2022 19:53:02 +0100

0. Preface

When brushing leetcode, the sort function is a commonly used method. It has not systematically summarized the usage before, resulting in that the code writing is not smooth enough every time and slows down the speed of understanding questions. Therefore, I decided to summarize the usage of the sort() function and take notes to deepen my impression

1, sort function definition (2 kinds)

  • Included in the #include header file. Remember to add it before use
// version1, the defau lt ascending sort is performed on the elements in the [first, last) area, that is, the < operator is used
template <class RandomAccessIterator>  
void sort ( RandomAccessIterator first, RandomAccessIterator last );  

// version2, sort the elements in the [first, last) area according to the specified mycomp sorting rule
// Here, mycomp can be a collation provided by the C++ STL standard library (such as STD:: greater < T >) or a custom collation.
template <class RandomAccessIterator, class Compare>  
void sort ( RandomAccessIterator first, RandomAccessIterator last, CompareFunction mycomp );  

2, Characteristics of sort function

  • Applicable objects: containers that support random access, that is, only sequential containers (vector, deque, array) are supported.
  • Sorting range: left closed right open, i.e. [).
  • In the second version definition, comp can be a collation provided by the C++ STL standard library (such as STD:: greater < T >) or a custom collation.
  • About the design principle of the custom parameter comp: comp takes two parameters of the same type. If the first parameter is in front of the second parameter, it returns true, otherwise it returns false.
  • Return value: none, because it changes the container directly through the iterator (pointer).
  • Sort in ascending order by default.
  • Unstable sorting: the relative order of the same elements cannot be guaranteed. The sort() function is implemented based on quick sorting. stable_sort() is stable.

3, Conditions to call sort() function

  • The iterator types supported by the container must be random access iterators, that is, vector, deque, array.
  • The sort() function is limited by the underlying implementation. It is only applicable to ordinary arrays and partially typed containers.
  • If the elements of the specified area in the container are sorted in ascending order by defau lt, the element type must support the < less than operator; Similarly, if other sorting rules provided by the standard library are selected, the element type must also support the comparison operator used in the underlying implementation of the rule;
  • When sorting, the sort() function needs to exchange the storage locations of elements in the container. In this case, if a custom class object is stored in the container, the move constructor and move assignment operator must be provided inside the class.

4, Other collations provided by the standard library

  • Less (less than)
  • Greater (greater than)
  • equal_ To (equal to)
  • not_ equal_ To (unequal)
  • less_ Equal (less than or equal to)
  • greater_ Equal (greater than or equal to)
  • Note: These are function objects / function objects. Pay attention to the format used when passing in. Add template parameters (because it is a template class) and the following (), such as less < int > ()

5, Custom collation

  • The custom comparison rule mycmp passed in by the sort function can be of two types
    Function pointer
    Function object or functor

Function Object is an object instantiated from a class (or structure) that overloads the operator() function. It looks like a function and is also called an imitation function.

5.1 using ordinary functions to realize user-defined sorting

  • The compare function in sort must be declared as a static member function or a global function. It cannot be used as an ordinary member function, that is, it cannot be written in a class; If it is written in a class, you also need to add the static keyword, otherwise an error will be reported.

Reason: 1) non static member functions can only be called by specific class objects; 2) std::sort functions are global, so it is not possible to call non static member functions in sort.
Instruction: static member functions or global functions are independent of specific objects and can be accessed independently without creating any object instances. At the same time, static member functions cannot call non static members of a class.

in short:

  • In class: use static keyword to modify;
  • Out of class: it is defined directly out of class without static keyword to make it a global function.

5.1.1 function defined in class - static keyword

  • Note: in line 9, because the value of the reference parameter cannot be changed, it is declared as a constant reference (decorated with const). Finally, I don't worry about this hhhh
#include <algorithm>
using namespace std;

class Solution {
public:
	// Custom sorting criteria, in class
	// Suppose the element type to be compared is vector < int >
	// Because the value of the reference parameter cannot be changed here, it is declared as a constant reference. Finally, I don't worry about this hhhh
	static bool cmp(const vector<int>& a, const vector<int>& b) {
        return a[0] > b[0] || (a[0] == b[0] && a[1] < b[1]);
    }
	
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        // Call sorting criteria
        sort(people.begin(), people.end(), cmp);
        vector<vector<int>> ans;
        for (const vector<int>& person: people) {
            ans.insert(ans.begin() + person[1], person);
        }
        return ans;
    }
};

5.1.2 functions defined outside class - Global

#include <algorithm>
using namespace std;

// Define global sorting criteria outside the class
bool cmp(const vector<int>& a, const vector<int>& b) {
        return a[0] > b[0] || (a[0] == b[0] && a[1] < b[1]);
}

class Solution {
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        // Call sorting criteria
        sort(people.begin(), people.end(), cmp);
        vector<vector<int>> ans;
        for (const vector<int>& person: people) {
            ans.insert(ans.begin() + person[1], person);
        }
        return ans;
    }
};

5.1.3 define directly in the sort function - this operation is very beautiful!!

However, it is only suitable for one-time use

#include <algorithm>
using namespace std;

class Solution {
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        // Define and call the sorting criteria directly inside the sort function
        sort(people.begin(), people.end(), [](const vector<int>& u, const vector<int>& v) {
            return u[0] > v[0] || (u[0] == v[0] && u[1] < v[1]);
        });
        vector<vector<int>> ans;
        for (const vector<int>& person: people) {
            ans.insert(ans.begin() + person[1], person);
        }
        return ans;
    }
};

5.2 realize user-defined sorting by using imitation function or function object

#include <algorithm>
using namespace std;

// Implement custom sorting rules by imitating functions
// Define function object classes
class Cmp {
public:
	//  Overload () operator
	bool operator() (const vector<int>& a, const vector<int>& b) {
		return a[0] > b[0] || (a[0] == b[0] && a[1] < b[1]);
	}
}mycmp;  // When defining, a class object is automatically created. We will explain the beauty of this definition later!

class Solution {
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        // Call sorting criteria
        //  sort(people.begin(), people.end(), Cmp);  //  Error reporting (mycopm does not refer to a value), parentheses need to be added
        sort(people.begin(), people.end(), Cmp())     // Correct, generate a temporary function object / functor
        sort(people.begin(), people.end(), mycmp)     // Correct, the step of creating temporary functor is omitted directly
        vector<vector<int>> ans;
        for (const vector<int>& person: people) {
            ans.insert(ans.begin() + person[1], person);
        }
        return ans;
    }
};

In addition, struct in C + + is very similar to class. Struct can also contain member variables and member functions. Therefore, in the above program, the function object class cmp can also be created using the struct keyword:

struct Cmp {
public:
	//  Overload () operator
	bool operator() (const vector<int>& a, const vector<int>& b) {
		return a[0] > b[0] || (a[0] == b[0] && a[1] < b[1]);
	}
}mycmp;

When defining a function object class, you can also define it as a template class
Note that this method must ensure that T-type elements can be compared directly with relational operators (such as the < operator here).
When calling, instantiate the template and specify the specific type

template <typename T>
class Cmp {
public:
	//  Overload () operator
	bool operator() (const T& a, const T& b) {
		return a[0] > b[0] || (a[0] == b[0] && a[1] < b[1]);
	}
}mycmp;

// Calling part of the code
myComp<vector<int>> my;
sort(people.begin(), people.end(), my);

Twists and turns

I don't know why. It just can't be combined, simplified and written in. It's always wrong

sort(people.begin(), people.end(), myComp()<vector<int>>);
// Line 29: Char 44: error: no viable constructor or deduction guide for deduction of template arguments of 'myComp'
//         sort(people.begin(), people.end(), myComp()<vector<int>>);
//                                            ^
// Line 7: Char 7: note: candidate template ignored: couldn't infer template argument 'T'
// class myComp {
//       ^
// Line 7: Char 7: note: candidate function template not viable: requires 1 argument, but 0 were provided

Error message analysis: the instantiation of the class template is missing. The class template can only be called after instantiation, but I already have it (pain mask)

// The following sentence can't be tested. Only separate instantiations can be successfully compiled
sort(people.begin(), people.end(), myComp<vector<int>>);
// Compilation error message: Line 29: char 63: error: expected '(' for function style cast or type construction
//        sort(people.begin(), people.end(), myComp<vector<int>>);
//                                           ~~~~~~~~~~~~~~~~~~~^
// 1 error generated.

Error message analysis: the instantiation of the class template is available, but there is a hint that the parentheses of the instantiation of the class are missing

dense willow trees and bright flowers

I don't know what's going on. A sudden flash of inspiration in my brain will tell me if the order of class instantiation and template instantiation is wrong. Sure enough, I'll know it as soon as I try!!! (finally solved)

Finally, I know why there is an error: the order of class instantiation and template instantiation is very important. The instantiation of class template is correct before class instantiation!!!!

sort(people.begin(), people.end(), myComp<vector<int>>());

5.3 overloading relational operators to realize user-defined sorting (three methods)

  • overall situation
  • Intra class member function
  • friend function

Topics: C++ Algorithm