这个星期看了侯捷先生《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); } }