这个星期看了侯捷先生《STL 源码剖析》算法部分,基本看完了,其中算法比较多,我就重点下Sort在SGI STL中的实现。
1. sort
函数的实现是这样的:
template <class RandomAccessIterator>
inline void sort(RandomIAccessIterator first , RandomAccessIterator last>
{
if ( first != last) {
__introsort_loop(fisrt,last, value_type(first), __lg( last - first ) * 2 );
__final_insertion_sort(first , last);
}
}
sort针对的是RandomAccessIterator(而像List容器是不能用这个sort,我在List的记录中详细的说明了List自定义的sort算法(QuickSort)),先调用函数__introsort_loop对其排序至大致有序,然后调用__final_insertion_sort函数实现完全排序;
1.1. __introsort_loop
首先对其进行QuickSort,如果分割行为有恶化为二次行为的倾向的时候(QuickSort最差的情况下时间复杂度是O(N^2)),那么这时候转而使用HeapSort,将时间复杂度维持在O(NlogN);
const int __stl_threshold = 16;
template <class RandomAccessIterator , class T , class Size)
void __introsort_loop (RandomAccessIterator first , RandomAccessIterator last , T* , Size depth_limit)
{
while ( last - first > __stl_threshold ) {
if (depth_limit == 0) {
partial_sort (first , last ,last);
return ;
}
--depth_limit;
RandomIAccessIterator cut = __unguarded_partition ( first , last , T(__median(*first , * (first + (last - first)/2))), *last);
__introsort_loop(cut , last , value_type(first) , depth_limit);
last = cut;
}
}
选择first,(first + (last - first) / 2),last - 1中一个够好的作为分割点,然后调用函数__unguarded_partition进行一次排序,使得比分割点值pivot小的在左边,大的在右边,然后递归调用__introsort_loop;
template <class RandomAccessIterator , class T>
RandomAccessIterator __unguarded_partition ( RandomAccessIterator first , RandomAccessIterator last , T pivot)
{
while (true) {
while ( *first < pivot ) ++first;
--last;
while ( *last > pivot ) --last;
if ( !(first < last) ) // only for random access iterator
return first;
iter_swap (first , last);
++first;
}
}
在出现分割恶化的情况下,调用函数partial_sort,该函数主要是HeapSort,关于堆排序我在下面说继续说明其实现;
template <class RandomAccessIterator>
inline void partial_sort (RandomAccessIterator first , RandomAccessIterator middle , RandomAccessIterator last)
{
__partial_sort (first , middle , last , value_type(first));
}
template <class RandomAccessIterator , class T>
inline void __partial_sort (RandomAccessIterator first , RandomAccessIterator middle , RandomAccessIterator last , T*)
{
make_heap (first , middle);
for (RandomAccessIterator i = middle ; i < last ; ++ i)
if ( *i < *first )
__pop_heap(first , middle , i ,T(*i) , distance_type(first));
sort_heap(first , middle);
}
1.2. __final_insertion_sort
Introspective Sorting之后,使得数列大致有序,然后使用插入排序,这样,会用更优的时间复杂度,插入排序的原理和实现比较简单,这里就不多说了;
template <class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first , RandomAccessIterator last)
{
if (last - first > __stl_threshold) {
__insertion_sort (first , first + __stl_threshold);
__unguarded_insertion_sort ( first + __stl_threshold , last);
}
else {
__insertion_sort(fisrt , last);
}
}
template <class RandomAccessIterator>
inline void __unguarded_insertion_sort(RandomAccessIterator first , RandomAccessIterator last)
{
__unguarded_insertion_sort_aux(first , last , value_type(first));
}
template <class RandomAccessIterator>
inline void __unguarded_insertion_sort_aux(RandomAccessIterator first , RandomAccessIterator last , T*)
{
for (RandomAccessIterator i = first ; i != last ; ++i)
__unguarded_linear_insert (i ,T(*i));
}
template <class RandomAccessIterator>
void __insertion_sort(RandomAccessIterator first ,ge RandomAccessIterator last)
{
if ( first == last) return;
for (RandomAccessIterator i = first + 1 ; i != last ; ++i) {
__linear_insert (first , i ,value_type(first));
}
}
template <class RandomAccessIterator>
void __linear_insert(RandomAccessIterator first , RandomAccessIterator last , T*)
{
T value = *last;
if (value < *first) {
copy_backward (first , last , last + 1);
*first = value;
}
else
__unguarded_insertion_sort(last , value);
}
template <class RandomAccessIterator , class T>
void __unguarded_insertion_sort(RandomAccessIterator last , T value)
{
RandomAccessIterator next = last;
--next;
while (value < *next) {
*last = *next;
last = next;
--next;
}
*last = value;
}
2. HeapSort
Binary Heap是一种complete binary tree,根据元素排队规则分为max-heap和min-heap,max-heap是最大值在根节点,因为Binary Heap是一种完全二叉树,就可以用数组来表述,
template <class RandomAccessIterator>
inline void make_heap(RandomAccessIterator first , RandomAccessIterator last)
{
__make_heap(first , last ,value_type(first) , distance_type(first));
}
template <class RandomAccessIterator , class T , class Distance>
void __make_heap(RandomIAccessIterator first , RandomAccessIterator last , T* , Distance *)
{
if (last - first < 2)
return;
Distance len = last - first;
Distance parent = (len - 2) / 2;
while (true) {
__adjust_heap(first , parent , len , T(*(first + parent)));
if (parent == 0)
return ;
parent--;
}
}
template <class RandomAccessIterator , class Distance , class T>
void __adjust_heap(RandomAccessIterator first , Distance holeIndex , Distance len , T value)
{
Distance topIndex = holeIndex;
Distance secondChild = 2 * holeIndex + 2;
while (secondChild < len) {
if (*(first + secondChild) < *(first + secondChild - 1))
--secondChild;
*(first + holeIndex) = *(first + secondChild);
holeIndex = secondChild;
secondChild = 2 * (secondChild + 1);
}
if (secondChild == len) {
*(first + holeIndex) = *(first + (secondChild - 1));
holeIndex = secondChild - 1;
}
__push_heap(first , holeIndex , topIndex , value);
}
template <class RandomAccessIterator>
inline void push_heap(RandomAccessIterator first , RandomAccessIterator last)
{
__push_heap_aux(first , last , distance_type(first),value_type(first));
}
template <class RandomAccessIterator , class Distance , class T>
inline void __push_heap_aux(RandomAccessIterator first , RandomAccessIterator last , Distance* , T*)
{
__push_heap(first , Distance((last - first) - 1) , Distance(0) , T(*(last - 1)));
}
template <class RandomAccessIterator , class Distance , class T>
inline void __push_heap(RandomAccessIterator first , Distance holeIndex , Distance topIndex, T value)
{
Distance parent = (holeIndex - 1) / 2;
while (holeIndex > topIndex && *(first + parent) < value) {
*(first + holeIndex) = *(first + parent);
holeIndex = parent;
parent = (holeIndex - 1) / 2;
}
*(first + holeIndex) = value;
}
template <class RandomAccessIterator>
inline void pop_heap(RandomAccessIterator first , RandomAccessIterator last)
{
__pop_heap_aux(first , last , value_type(first));
}
template <class RandomAccessIterator , class T>
inline void __pop_heap_aux(RandomAccessIterator first , RandomAccessIterator last , T* value)
{
__pop_heap(first , last - 1 , last - 1 , T(*(last - 1)) , distance_type(first));
}
template <class RandomAccessIterator , class T , class Distance>
inline void __pop_heap(RandomAccessIterator first , RandomAccessIterator last , RandomAccessIterator result , T value , Distance*)
{
*result = *first;
__adjust_heap(first , Distance(0) , Distance(last - first) , value);
}
3. merge sort
归并排序在STL中的实现借用函数inplace
template <class BidirectionalIter>
void mergesort(BidirectionalIter first , BidirectionalIter last )
{
typename iterator_traits<BidirectionalIter> :: difference_type n = distance(first , last);
if ( n == 0 || n == 1)
return ;
else {
BidirectionalIter mid = first + n / 2;
mergesort(first , mid);
mergesort(mid , last);
inplace_merge(first , mid , last);
}
}