Popular Science: What did std :: sort

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

Guess you like

Origin www.cnblogs.com/Iamafool/p/11587612.html