STL std :: sort considered in comparison to OIer friendly functions, but have you thought about how to ensure that it is the sort of high-speed and stable?
We first came to the first layer: sort function
Template <typename _RandomAccessIterator> inline void Sort (_RandomAccessIterator __first, _RandomAccessIterator __last) { // the application using the random access iterators __glibcxx_function_requires (_Mutable_RandomAccessIteratorConcept <_RandomAccessIterator> ) // application using the built __gnu_cxx :: __ ops :: __ iter_less_iter function __glibcxx_function_requires (_LessThanComparableConcept < iterator_traits typename <_RandomAccessIterator> :: the value_type> ) // declare valid section __glibcxx_requires_valid_range (__ First, __last); // push the pot to std :: __ sort function std :: __ sort (__ first, __last, __gnu_cxx :: __ ops :: __ iter_less_iter () ); }
This layer actually did not do, just put the pot pushed to the second floor: __ sort function
Template <typename _RandomAccessIterator, typename _Compare> inline void __sort (_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { IF (__first! = __last) { // limited to O (n log n) sorting (excellent complexity, but the constant ), almost ordered data STD introsort_loop :: __ (__ First, __last, LG STD :: __ (__ Last - __first) * 2 , __comp); // when the data representing ordered, relatively small by a constant insertion sort (complexity difference, but the constants excellent) STD :: __ final_insertion_sort (__ First, __last, __comp); } }
Here we can see the magic of the great God who operate in those days: the different methods of sorting their duties, learn from each other
Next we separately, first look at the O (n log n) partial ordering: __ introsort_loop function
In all O (n log n) sort, the constant was undoubtedly the best quick sort, it naturally became the first choice to achieve O (n log n) sorting
Of course, the direct use of quick sort is likely to be jammed, so we use an additional function fallback
Template <typename _RandomAccessIterator, _size typename, typename _Compare> void __introsort_loop (_RandomAccessIterator __first, _RandomAccessIterator __last, _size __depth_limit, _Compare __comp) { // If the sorting section, affecting the efficiency of the complexity of the algorithm exceeds the length, using the quick sorting the while (__last - __first> int (_S_threshold)) { // if the number of layers is too large quick sort, quicksort unfriendly description data IF (__depth_limit == 0 ) { // switch hEAPSORT std :: __ partial_sort ( __first, __last, __last, __comp); return ; } - __depth_limit; // the data into two sets __Cut = _RandomAccessIterator std :: __ unguarded_partition_pivot (__ First, __last, __comp); // After half a recursive sort std :: __ introsort_loop (__ Cut, __last, __depth_limit, __comp); // continue ordering the first half __last = __cut; // In fact, this the method is very show, will only increase the downward recursive, another cycle instead of using // impact on the recursive stack space smaller than a lot of direct twice } }
Whispered BB: Select this reference value is too casual: __ unguarded_partition_pivot function
Template <typename _RandomAccessIterator, typename _Compare> inline _RandomAccessIterator __unguarded_partition_pivot (_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { // select the intermediate value _RandomAccessIterator __mid = __first + (__last - __first) / 2 ; // Select first + 1, mid, last - a median of three positions as a reference value and stores this position in the first // inside the function realized too violent, all if (further violent than violence), will not come out std :: __ move_median_to_first (__first, __first + . 1 , __mid, __last - . 1 , __comp); // fast moving discharge standards, realize a return STD :: __ unguarded_partition (First + __ . 1 , __last, __first, __comp); } Template<typename _RandomAccessIterator, typename _Compare> _RandomAccessIterator __unguarded_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, _RandomAccessIterator __pivot, _Compare __comp) { //标准的快速排序 while (true) { while (__comp(__first, __pivot)) ++__first; --__last; while (__comp(__pivot, __last)) --__last; if (!(__first < __last)) return __first; std::iter_swap(__first, __last); ++__first; } }
If the card is too quick sort, heap sort to use: __ partial_sort function
Template <typename _RandomAccessIterator, typename _Compare> inline void __partial_sort (_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, _Compare __comp) { // build stack std :: __ heap_select (__ First, __middle, __last, __comp); // projectile stack std :: __sort_heap (__ First, __middle, __comp); } Template <typename _RandomAccessIterator, typename _Compare> void __heap_select (_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, _Compare __comp) { // build stack // estimation algorithm is used to obtain the maximum priority heap the multiple elements, all have an empty cycle std::__make_heap(__first, __middle, __comp); for (_RandomAccessIterator __i = __middle; __i < __last; ++__i) if (__comp(__i, __first)) std::__pop_heap(__first, __middle, __i, __comp); } template<typename _RandomAccessIterator, typename _Compare> void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType; typedef typename iterator_traits<_RandomAccessIterator>::difference_type _DistanceType; if (__last - __first < 2) return; const _DistanceType __len = __last - __first; _DistanceType __parent = (__len - 2) / 2; while (true) { //从堆底向堆顶更新 _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent)); std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value), __comp); if (__parent == 0) return; __parent--; } } template<typename _RandomAccessIterator, typename _Compare> void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { //pop and pop while (__last - __first > 1) { --__last; std::__pop_heap(__first, __last, __last, __comp); } }
Of course, STL continues the consistent big constants "fathers of the law," adjustment stack and heap bombs are so complicated
template<typename _RandomAccessIterator, typename _Distance, typename _Tp, typename _Compare> void __push_heap(_RandomAccessIterator __first, _Distance __holeIndex, _Distance __topIndex, _Tp __value, _Compare __comp) { //向上跳,直到堆稳定为止 _Distance __parent = (__holeIndex - 1) / 2; while (__holeIndex > __topIndex && __comp(__first + __parent, __value)) { *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent)); __holeIndex = __parent; __parent = (__holeIndex - 1) / 2; } * (__ First + __holeIndex) = _GLIBCXX_MOVE (__ value); } Template <typename _RandomAccessIterator, typename _Distance, typename _TP, typename _Compare> void __adjust_heap (_RandomAccessIterator __first, _Distance __holeIndex, _Distance __len, _TP the __value, _Compare __comp) { // adjust stack @ adjustment method: the first end of the stack to move no brain, then update upwardly const _Distance __topIndex = __holeIndex; _Distance __secondChild = __holeIndex; the while (__secondChild <(__len - . 1 ) / 2 ) { __secondChild = 2 * (+ __secondChild. 1 ); IF (__comp (__ First + __secondChild, __first + (__secondChild - . 1 ))) __secondChild -; // Select higher priority son * (__ First + __holeIndex) = _GLIBCXX_MOVE (* (__ First + __secondChild)); __holeIndex = __secondChild; // downward adjustment } // If only one son IF ((& __len . 1 ) == 0 && __secondChild == (__len - 2 ) / 2 ) { __secondChild = 2 * (+ __secondChild . 1 ); *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + (__secondChild - 1))); __holeIndex = __secondChild - 1; } //向上更新 std::__push_heap(__first, __holeIndex, __topIndex, _GLIBCXX_MOVE(__value), __gnu_cxx::__ops::__iter_comp_val(__comp)); } template<typename _RandomAccessIterator, typename _Compare> inline void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _RandomAccessIterator __result, _Compare __comp) { typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType; typedef typename iterator_traits<_RandomAccessIterator>::difference_type _DistanceType; //删除堆顶 _ValueType __value = _GLIBCXX_MOVE(*__result); *__result = _GLIBCXX_MOVE(*__first); //调整堆 std::__adjust_heap(__first, _DistanceType(0), _DistanceType(__last - __first), _GLIBCXX_MOVE(__value), __comp); }
When more orderly, we can optimize the use insertion sort constant: __ final_insertion_sort function
Template <typename _RandomAccessIterator, typename _Compare> void __final_insertion_sort (_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { IF (__last - __first> int (_S_threshold)) { // begin first ordered sequence, as later insertion sort of pre-sorted section std :: __ insertion_sort (__ First, __first + int (_S_threshold), __comp); // the back of all the elements sorted STD :: __ unguarded_insertion_sort (__ First + int (_S_threshold), __last, __comp); } the else STD :: __ insertion_sort (__ First, __last, __comp); // if the sequence is short, direct ordering }
Implementation is very simple, just a little strange operation:
Template <typename _RandomAccessIterator, typename _Compare> void __insertion_sort (_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { IF (__first == __last) return ; // standard insertion sort for (+ _RandomAccessIterator __i = __first . 1 ; __i = __last!; ++ __i) { // If the insertion position for the opening sequence, then move directly to the entire sequence? ? ? // What Sao operation? ? ? IF (__comp (__ I, __first)) { typename iterator_traits <_RandomAccessIterator> :: = _GLIBCXX_MOVE the value_type __val (* __i); _GLIBCXX_MOVE_BACKWARD3 (__ First, __i, __i + . 1 ); * __ First = _GLIBCXX_MOVE (__ Val); } // otherwise, in accordance with standard insertion sort to do the else STD :: __ unguarded_linear_insert (__ I, __gnu_cxx :: __ OPS :: __ val_comp_iter (__ CoMP)); } } Template <typename _RandomAccessIterator, typename _Compare> inline void __unguarded_insertion_sort (_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { // out of honest insertion sort for (_RandomAccessIterator __i = __first; __i = __last;! ++ __i) std::__unguarded_linear_insert(__i, __gnu_cxx::__ops::__val_comp_iter(__comp)); } template<typename _RandomAccessIterator, typename _Compare> void __unguarded_linear_insert(_RandomAccessIterator __last, _Compare __comp) { //别看了,这真的就是插入排序 typename iterator_traits<_RandomAccessIterator>::value_type __val = _GLIBCXX_MOVE(*__last); _RandomAccessIterator __next = __last; --__next; while (__comp(__val, __next)) { *__last = _GLIBCXX_MOVE(*__next); __last = __next; --__next; } *__last = _GLIBCXX_MOVE(__val); }
In fact, I really had to test, when the basic order, faster than insertion sort row is really slow (constant too large)
Summary, the realization sort of like this:
Sort (the begin *, * End) { __sort ( * the begin, * End) { __introsort_loop ( * the begin, * End, Floor) { IF ( / * interval greater length * / ) { IF ( / * recursive layers is too large * / ) { // hEAPSORT __partial_sort (the begin *, * End); } // selecting a reference value, and the separation of elements __cut = __unguarded_partition_pivot (the begin *, * End) // partition __introsort_loop (the begin *, * __cut); __introsort_loop ( * __ Cut, * End); } } __final_insertion_sort ( * the begin, * End) { // insertion sort } } }
Ignorant force ~~~
Look at the code to see dizziness
- Would someone