- 只接受
RandomAccess Iterator
,list
和slist
使用自己提供的member functions sort()
STL - Sort()
:
- 数据量大时采用
Quick Sort
分段递归排序; - 分段后的数据量小于某个门槛,为避免递归调用的额外负荷,改用
Insertion Sort
; - 若递归层次过深,改用
Heap Sort
实现如下:
template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last) {
if (first != last) {
__introsort_loop(first, last, value_type(first), __lg(last - first) * 2);
__final_insertion_sort(first, last);
}
}
先进行内省式快速排序(introsort
):
template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first,
RandomAccessIterator last, T*,
Size depth_limit) {
while (last - first > __stl_threshold) { // > 16
if (depth_limit == 0) {
partial_sort(first, last, last); //递归过深,采用堆排序
return;
}
--depth_limit;
RandomAccessIterator cut = __unguarded_partition
(first, last, T(__median(*first, *(first + (last - first)/2),
*(last - 1))));
__introsort_loop(cut, last, value_type(first), depth_limit);
last = cut; // 对左半端sort,这样写减少递归次数
}
}
之后对若干个具有不同排序程度的子序列进行插入排序,__lg()
控制分割恶化的情况。
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(first, last);
}
最后的插入排序,先判断是否大于阈值,若小于则直接进行一次插入排序,省时省力。
若大于阈值,则分为两部分:
- 普通插入排序
__insertion_sort
- 不需要边界检查的插入排序
__unguarded_insertion_sort
区别:
__insert_sort
:
它会先将该值和第一个元素进行比较,如果比第一个元素还小,那么就直接将前面已经排列好的数据整体向后移动一位,然后将该元素放在起始位置。对于这种情况,和标准插入排序相比,它将last - first - 1次的比较与交换操作变成了一次copy_backward操作,节省了每次移动前的比较操作
如果该元素并不小于第一个元素,它会调用另外一个函数__unguarded_linear_insert,这里仅仅挨个判断是否需要调换,找到位置之后就将其插入到适当位置,而无需检测是否到达边界。
这里是因为if
处不执行已经明确了,最小值在左侧,故不到边界便可停止。
template <class RandomAccessIterator, class T>
void __unguarded_linear_insert(RandomAccessIterator last, T value) {
RandomAccessIterator next = last;
--next;
while (value < *next) {
*last = *next;
last = next;
--next;
}
*last = value;
}
template <class RandomAccessIterator, class T>
inline void __linear_insert(RandomAccessIterator first,
RandomAccessIterator last, T*) {
T value = *last;
if (value < *first) {
copy_backward(first, last, last + 1);
*first = value;
}
else
__unguarded_linear_insert(last, value);
}
template <class RandomAccessIterator>
void __insertion_sort(RandomAccessIterator first, RandomAccessIterator last) {
if (first == last) return;
for (RandomAccessIterator i = first + 1; i != last; ++i)
__linear_insert(first, i, value_type(first));
}
__unguarded_insertion_sort
:
template <class RandomAccessIterator, class T>
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>
inline void __unguarded_insertion_sort(RandomAccessIterator first,
RandomAccessIterator last) {
__unguarded_insertion_sort_aux(first, last, value_type(first));
}
使用此函数时,一定得确保这个区间的左边有效范围内已经有了最小值,否则不检查边界的后果很严重。
将经过
__introsort_loop
排序的数据分成两段,假设第一段里面包含了最小值,那么将第一段使用__insertion_sort
排序,后一段使用__unguarded_insertion_sort
便可以达到效率的最大化.
这就是__final_insertion_sort
所采用的:
template <class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first,
RandomAccessIterator last) {
if (last - first > __stl_threshold) {
// 快排性质决定了左边元素比右边区间元素小,可以证明最小元素在前16个元素内
__insertion_sort(first, first + __stl_threshold);
// 确定了最小值在左边后,便可调用无边界检查的快速排序
__unguarded_insertion_sort(first + __stl_threshold, last);
}
else
__insertion_sort(first, last);
}
快排性质决定了左边元素比右边区间元素小,可以证明最小元素在前16个元素内。 确定了最小值在左边后,便可调用无边界检查的快速排序。