Detailed explanation of STL sorting (sort)

Http://www.cppblog.com/mzty/archive/2005/12/15/1770.html

Detailed explanation of STL sorting (sort) Author winter

- Detailed explanation of STL sorting (sort)
- 0 Preface: STL, why do you have to master
- 1 the sort algorithm provided by the STL
- 1.1 Introduction to all sort algorithms
- The comparison function in 1.2 sort
- Stability of the 1.3 sort
- 1.4 Full Order
- 1.5 Local sorting
- 1.6 Nth_element specifying element ordering
- 1.7 Partition and Stable_partition

- 2 Sort and container
- 3 Selecting the appropriate sorting function
- 4 Summary
- 5 Reference documents

*all complex sorting operations, can be easily achieved through the STL* !

0 Preface: STL, why do you have to master For programmers, the data structure is a compulsory course. From find to sort, from linked list to two fork tree, almost all the algorithms and principles need to be understood, not understood and memorized. Fortunately, these theories are already relatively mature, the algorithm is basically fixed down, do not need you to spend your mind to consider the principle of the algorithm, and do not have to verify its accuracy. However, when you start to work in a computer language, you will find that you need to repeat the mature algorithms again and again in the face of different needs, and you will be caught in some bugs that are inadvertently generated by yourself. At this point, you want to find a tool that has helped you implement these features and how you can use them to do so without compromising performance. What you need is STL, Standard Template Library!

There is a proverb in the West: Don't invent the wheel again!

STL almost encapsulates all the algorithms in the data structure, from the list to the queue, from vectors to stacks, to hash to two forks, from search to sort, from add to delete ... It can be said that if you understand the STL, you will find that you do not have to adhere to the algorithm itself, so standing on the shoulders of giants to consider more advanced applications.

Sorting is one of the most widely used algorithms, this paper introduces in detail the usage and difference of different sorting algorithms in STL.

1 the sort algorithm provided by the STL C + + is so many people like it, because it has the concept of object-oriented, but also maintain the high efficiency of C language features. The STL sorting algorithm also needs to remain efficient. Therefore, for different requirements, STL provides different functions, different functions, the implementation of the algorithm is different. 1.1 All sort algorithms describe all the parameters of the sort algorithm that need to be entered in a range, [begin, end]. The iterator used here (iterator) needs to be a random iterator (radomaccessiterator), that is, an iterator that can be randomly accessed, such as: It+n or something. (except partition and stable_partition)

If you need to define a comparison function yourself, you can pass in your defined copy function (functor) as a parameter. Each of these algorithms supports incoming comparison functions. The following is a list of the names of all STL sort algorithm functions:

Name of function |
function Description |

Sort |
Sort all elements of a given interval |

Stable_sort |
Stable ordering of all elements in a given interval |

Partial_sort |
Sort all elements of a given interval |

Partial_sort_copy |
Copy and sort the given interval |

Nth_element |
Find the element corresponding to a position in a given interval |

is_sorted |
Determine if an interval has been sequenced. |

Partition |
Put elements that meet a certain condition in front |

Stable_partition |
Relatively stable so that elements that meet a certain condition are placed in front |

Where Nth_element is the most difficult to understand, in fact, this function is used to find out the first few. For example: To find the value of the middle number in an array of 7 elements, at which point I may not care about the front or the back, I only care what the value of the element in the fourth bit is.

Comparison functions in 1.2 sort when you need to sort in a particular way, you need to specify a comparison function for sort, or the program will automatically provide you with a comparison function.

int > Vect; //... Sort (Vect.begin (), Vect.end ()); //This is equivalent to calling sort (vect.begin (), Vect.end (), less<int> ());

In the example above, the system itself provides less functor for sort. Other functor functions are provided in the STL, and the following is a list of the functor functions:

name |
function Description |

Equal_to |
Equal |

Not_equal_to |
Not equal |

Less |
Less than |

Greater |
Greater than |

Less_equal |
Less than or equal |

Greater_equal |
Greater than or equal |

It is important to note that these functions are not all suitable for your sort algorithm, how to choose, and decide on your application. In addition, you cannot write the name of the functor directly, but instead write its overloaded () function:

Less<int> () greater<int> ()

You can use these function templates directly when the elements in your container are in some standard type (int float char) or string. But if you define your own type or you need to sort by other means, there are two ways you can achieve this: one is to write your own comparison function. The other is an overloaded type of ' < ' operation assignment.

#include<iostream>#include<algorithm>#include<functional>#include<vector>using namespaceStdclassMyClass { Public: MyClass (intAintb): First (a), second (b) {}intFirstintSecondBOOL operator< (ConstMyClass &m)Const{returnFirst < M.first; }};BOOLLess_second (ConstMyClass & M1,ConstMyClass & m2) {returnM1.second < M2.second;}intMain () {vector< MyClass > Vect; for(inti = 0; I < 10; i + +) {MyClass my (10-i, i*3); Vect.push_back (my); } for(inti = 0; I < vect.size (); i + +) cout<< "("<<vect[i].first<<","<<vect[i].second<<") \ n"; Sort (Vect.begin (), Vect.end ()); cout<< "After sorted by first :"<<endl; for(inti = 0; I < vect.size (); i + +) cout<< "("<<vect[i].first<<","<<vect[i].second<<") \ n"; cout<< "After sorted by second:"<<endl; Sort (Vect.begin (), Vect.end (), Less_second); for(inti = 0; I < vect.size (); i + +) cout<< "("<<vect[i].first<<","<<vect[i].second<<") \ n";return0;}

Know what the output is:

(10,0) (9,3) (8,6) (7,9) (6,12) (5,15) (4,18) (3,21) (2,24) (1,27) after sorted by first: (1,27) (2,24) (3,21) (4,18) (5,15) (6,12) (7,9) (8,6) (9,3) (10,0) following sorted by second: (10,0) ( 9,3) (8,6) (7,9) (6,12) (5,15) (4,18) (3,21) (2,24)

1.3 Sort stability you find it strange to have sort and stable_sort, as well as partition and stable_partition. The difference is that a function with stable guarantees that the original relative order of the equal elements will remain unchanged after sorting. Perhaps you will ask, since the equal, you still control his relative position, also don't know who is who? Here's a question to figure out, the equivalence here is that the function you provide means that two elements are equal and not necessarily a touch of the same element.

For example, if you write a comparison function:

bool Less_len (constconst string &str2) { return str1.length () < Str2.length ();}

At this point, "Apple" and "winter" are equal, if "apple" appears in front of "winter", with stable functions sorted, their order must be the same, if you use a function without "stable" sort, then after sorting, " Winter "may be in front of" Apple ".

1.4 Full sort all the elements in the given range are arranged in the order of the size relationship. Functions that are used for full ordering are

Template<classRandomaccessiterator>voidSort (randomaccessiterator first, Randomaccessiterator last);Template<classRandomaccessiterator,classStrictweakordering>voidSort (randomaccessiterator First, randomaccessiterator last,strictweakordering comp);Template<classRandomaccessiterator>voidStable_sort (randomaccessiterator First, Randomaccessiterator last);Template<classRandomaccessiterator,classStrictweakordering>voidStable_sort (randomaccessiterator First, Randomaccessiterator last, strictweakordering comp);

In the 1th, 3 forms, sort and stable_sort do not specify a comparison function, and the system uses operator< to sort all elements in the interval [first,last] By default, so if you are using a type that the rebel has overloaded operator < function, then you can worry about it. 2nd, 4 forms, you can arbitrarily specify the comparison function, the application is more flexible. Take a look at the actual application:

There are 10 students in the class, I want to know their grades.

#include<iostream>#include<algorithm>#include<functional>#include<vector>#include<string>using namespaceStdclassstudent{ Public: Student (ConstString &a,intb): Name (a), score (b) {} string name;intScore;BOOL operator< (ConstStudent &m)Const{returnscore< M.score; }};intMain () {vector< student> vect; Student St1 ("Tom", 74); Vect.push_back (ST1); St1.name= "Jimy"; st1.score=56; Vect.push_back (ST1); St1.name= "Mary"; st1.score=92; Vect.push_back (ST1); St1.name= "Jessy"; st1.score=85; Vect.push_back (ST1); St1.name= "Jone"; st1.score=56; Vect.push_back (ST1); St1.name= "Bush"; st1.score=52; Vect.push_back (ST1); St1.name= "Winter"; st1.score=77; Vect.push_back (ST1); St1.name= "Andyer"; st1.score=63; Vect.push_back (ST1); St1.name= "Lily"; st1.score=76; Vect.push_back (ST1); St1.name= "Maryia"; st1.score=89; Vect.push_back (ST1); cout<< "------before sort ..."<<endl; for(inti = 0; I < vect.size (); i + +) cout<<vect[i].name<< ": \ t"<<vect[i].score<<endl; Stable_sort (Vect.begin (), Vect.end (),less<student> ()); cout << "-----After sort ...."<<endl; for(inti = 0; I < vect.size (); i + +) cout<<vect[i].name<< ": \ t"<<vect[i].score<<endl;return0;}

Its output is:

------before sort ... Tom: 74Jimy: 56Mary: 92Jessy: 85Jone: 56Bush: 52winter:77andyer:63lily: 76Maryia: -----after sort .... Bush: 52Jimy: 56Jone: 56andyer:63tom: 74Lily: 76winter:77jessy: 85maryia:89mary: 92

Sort uses a sophisticated "fast-sorting algorithm" (most of the STL versions are now not simple, fast-sorting, but with interpolated sorting algorithms). Note 1, can guarantee a good average performance, the complexity of N*log (n), because the simple fast ordering in theory has the worst case, the performance is very low, its algorithm complexity is n*n, but most of the STL version has been optimized in this area, so you can rest assured that use. Stable_sort uses a "merge sort", allocating enough memory to be N*log (n), otherwise its complexity is N*log (n) *log (n), which has the advantage of keeping the relative positions between equal elements consistent before and after sorting. 1.5 Local Sort local ordering is actually a sort of order that is provided to reduce unnecessary operations. Its function prototypes are:

Template<classRandomaccessiterator>voidPartial_sort (randomaccessiterator First, Randomaccessiterator middle,randomaccessiterator last);Template<classRandomaccessiterator,classStrictweakordering>voidPartial_sort (Randomaccessiterator first,randomaccessiterator middle,randomaccessiterator last, StrictWeakOrdering comp);Template<classInputiterator,classRandomaccessiterator>randomaccessiterator partial_sort_copy (inputiterator First, Inputiterator last, Randomaccessiterator result_first,randomaccessiterator result_last);Template<classInputiterator,classRandomaccessiterator,classStrictweakordering>randomaccessiterator partial_sort_copy (inputiterator First, Inputiterator last, Randomaccessiterator result_first,randomaccessiterator result_last, Compare comp);

After understanding the sort and stable_sort, it's easier to understand Partial_sort. Let's look at its purpose: There are 10 students in the class, and I want to know who is the 5 who have the lowest score. If you don't have a partial_sort, you need to sort all the people in order and then take the top 5. Now you just need to sort the score by a minimum of 5, and make the following changes to the above program:

Stable_sort (Vect.begin (), Vect.end (),less<student> ()), replaced by: Partial_sort (Vect.begin (), Vect.begin () +5, Vect.end (),less<student> ());

The output is:

------before sort ... Tom: 74Jimy: 56Mary: 92Jessy: 85Jone: 56Bush: 52winter:77andyer:63lily: 76Maryia: -----after sort .... Bush: 52Jimy: 56Jone: 56andyer:63tom: 74Mary: 92Jessy: 85winter:77lily: 76maryia:89

Do you know the benefits? When the amount of data is small may not see the advantage, if it is 1 million students, I want to find the lowest score of 5 people ...

The heap ordering (heapsort) used by Partial_sort is N*log (n) in any case. If you want to use Partial_sort to achieve full ordering, you just have to let middle=last.

Partial_sort_copy is actually a combination of copy and Partial_sort. The number of sorted (copied) is [first, last] and [Result_first, result_last) the smaller interval. If the [Result_first, Result_last] interval is greater than the [first, last] interval, then the partial_sort is equivalent to the combination of copy and sort.

1.6 nth_element Specifies the ordering of elements nth_element an easy-to-read but confusing sort of explanation. It is more convenient to use examples:

There are 10 students in the class, and I want to know the students who are ranked in the bottom 4th place.

If you want to meet the above requirements, you can use sort order, and then take the 4th bit (because it is from the small to the big row), the more intelligent friends will use Partial_sort, only the top 4, and then get 4th place. In fact this is you or waste, because the first two bits you do not need to sort at all, at this time, you need nth_element:

Template <class randomaccessiterator>void nth_element (randomaccessiterator First, Randomaccessiterator Nth,randomaccessiterator last); Template <classclass strictweakordering>void nth_element ( Randomaccessiterator First, Randomaccessiterator Nth,randomaccessiterator last, strictweakordering comp);

For the above instance requirements, you only need to modify the program in 1.4 as follows:

Stable_sort (Vect.begin (), Vect.end (),less<student> ()), replaced by: Nth_element (Vect.begin (), Vect.begin () +3, Vect.end (),less<student> ());

The result of the operation is:

------before sort ... Tom: 74Jimy: 56Mary: 92Jessy: 85Jone: 56Bush: 52winter:77andyer:63lily: 76Maryia: -----after sort .... Jone: 56Bush: 52Jimy: 56andyer:63jessy: 85Mary: 92winter:77tom: 74Lily: 76maryia:89

Who's the fourth one? Andyer, this unlucky fellow. Why is begin () +3 instead of +4? I did not care when I began to write this article, and later, in ILOVEVC's reminder, I found this problem. Begin () is the first, begin () +1 is the second, ... begin () +3 of course it's the fourth one. 1.7 Partition and Stable_partition as if these two functions are not used for sorting, the ' classification ' algorithm will be more appropriate. Partition is to divide the elements of an interval into two categories according to a certain condition. Its function prototypes are:

Template <class predicate>forwarditerator partition (ForwardIterator first, ForwardIterator last, predicate pred)Template <classclass predicate> ForwardIterator stable_partition (forwarditerator first, ForwardIterator last, predicate pred);

Take a look at the app: 10 students in the class, counting all the students who didn't pass (less than 60 points). You only need to replace the program in 1.4 with the following format:

Stable_sort (Vect.begin (), Vect.end (),less<student> ()), replaced by: Student Exam ("pass"; stable_ Partition (Vect.begin (), Vect.end (), bind2nd (less<student> (), exam));

The output is:

------before sort ... Tom: 74Jimy: 56Mary: 92Jessy: 85Jone: 56Bush: 52winter:77andyer:63lily: 76Maryia: -----after sort .... Jimy: 56Jone: 56Bush: 52Tom: 74Mary: 92Jessy: 85winter:77andyer:63lily: 76maryia:89

See, Jimy,jone, Bush (no wonder the American president is stupid) failed. and using stable_partition, the relative order between the elements is unchanged. 2 Sort and container The standard container in STL is the main vector, list, deque, String, set, Multiset, map, Multimay, where set, Multiset, map, and Multimap all store their elements in a tree-structured manner. See: Learn the STL map, STL set data Structure Foundation. So in these containers, the elements are always orderly.

The iterator type of these containers is not a random iterator, so those sorting functions above are not available for these containers. The above sort functions are available for the following containers:

If you define a container that also supports random iterators, there is no problem with sorting algorithms.

For the list container, the list comes with a sort member function List::sort (). It is similar to the sort in the algorithm function, but List::sort is a pointer-based sort, which means that all data movement and comparisons are implemented by pointers, so that the ordered iterator remains valid (the sort iterator in the vector is invalidated).

3 Selecting the appropriate sorting function Why choose the right sort function? Maybe you don't care about efficiency (the efficiency here is the program run time), or you have a small amount of data, so you think it doesn't matter which function to use.

In fact, even if you do not care about efficiency, if you choose the appropriate sorting function, you will make your code easier to understand, you will make your code more extensibility, gradually develop a good habit, it is important.

If you've ever used qsort in C and want to know how qsort compares to them, I'll tell you that qsort and sort are the same, because they're all quick to sort. In terms of efficiency, the following sort algorithms are sorted, with efficiency from high to low (time consuming from small to large):

- Partion
- Stable_partition
- Nth_element
- Partial_sort
- Sort
- Stable_sort

Remember, the previous translation of the effective STL article, which summarizes how to select the sorting function is very good:

- To sort vectors, strings, deque, or array containers, you can choose sort or stable_sort;
- If you only need to get top n elements in the vector, string, deque, or array container, the partial sort partial_sort is preferred.
- For a vector, string, deque, or array container, you need to find the nth position element or you need to get top N and do not relate to the internal order of top N, Nth_element is ideal;
- If you need to separate an element that satisfies a condition or does not satisfy a condition from a standard sequence container or array, you might want to use partition or stable_partition;
- If you use the list container, you can use the partition and Stable_partition algorithms directly, and you can use List::sort instead of sort and stable_sort sorting. If you need to get a partial_sort or nth_element sort effect, you have to use it indirectly. As described above, there are several ways to choose.

In short, remember a word:

**if you want to save time, do not detour, also do not take the unnecessary road!**4 Summary The discussion technology is like a bottomless pit, often easily by a point can be extended to another countless technical points. Therefore, you need to look at the problem from a global perspective, just like observing the sort algorithm in STL. In fact, there are make_heap, sort_heap and other sorting algorithms in STL. This article does not mention. This paper explains the characteristics of the sorting algorithm in STL, and summarizes how to choose the appropriate algorithm in the actual situation.

5 Reference Document Article 31: How to select a sort function

The standard librarian:sorting in the standard Library

Effective STL Chinese Version

Standard Template Library Programmer ' s Guide vvvv

C + + STL sort struct Comp