首页 > 代码库 > STL Sort Algorithm

STL Sort Algorithm

这个星期看了侯捷先生《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 = http://www.mamicode.com/*last;>
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);
	}
}




STL Sort Algorithm