分析下sort源码
sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_function_requires(_LessThanComparableConcept<
typename iterator_traits<_RandomAccessIterator>::value_type>)
__glibcxx_requires_valid_range(__first, __last);
__glibcxx_requires_irreflexive(__first, __last);
std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());
}
这段代码的作用是对指定范围内的元素进行排序,使用的排序算法是 std::__sort。排序的顺序由 __gnu_cxx::__ops::__iter_less_iter() 指定。
下面分析std::__sort
__sort(_RandomAccessIterator __first, _RandomAccessIterator __last,_Compare __comp)
{
if (__first != __last)
{
std::__introsort_loop(__first, __last,std::__lg(__last - __first) * 2,__comp);
std::__final_insertion_sort(__first, __last, __comp);
}
}
这个函数的主要逻辑是:
- 检查要排序的范围是否为空,如果为空则无需进行排序。
- 使用
std::__introsort_loop函数进行快速排序。这是一种混合排序算法,首先使用快速排序,但在递归深度超过一定阈值时,切换到堆排序。 - 使用
std::__final_insertion_sort函数进行最终的插入排序。插入排序对小型范围的元素进行高效排序。
这个混合排序的策略可以在大多数情况下保持较好的性能,因为快速排序在大部分情况下表现良好,而插入排序适用于小规模的数据。
接下来分别查看:__introsort_loop 和__final_insertion_sort
__introsort_loop(_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Size __depth_limit, _Compare __comp)
{
while (__last - __first > int(_S_threshold))
{
if (__depth_limit == 0)
{
std::__partial_sort(__first, __last, __last, __comp);
return;
}
--__depth_limit;
_RandomAccessIterator __cut =
std::__unguarded_partition_pivot(__first, __last, __comp);
std::__introsort_loop(__cut, __last, __depth_limit, __comp);
__last = __cut;
}
}
- 使用
while循环迭代排序范围,直到范围的大小小于_S_threshold(一个阈值,通常是快速排序切换到插入排序的阈值)。 - 如果递归深度达到了预定的深度限制(
__depth_limit == 0),则切换到堆排序。这是为了避免快速排序的最坏情况下的性能问题。 - 否则,使用
std::__unguarded_partition_pivot函数分割数组,并对分割后的子数组进行递归快速排序。然后更新排序范围__last。 - 循环直到排序范围的大小小于
_S_threshold。
这段代码的作用是执行快速排序的主要循环部分,通过分割数组并递归地对子数组进行排序来完成整个排序过程。
__final_insertion_sort(_RandomAccessIterator __first,_RandomAccessIterator __last, _Compare __comp)
{
if (__last - __first > int(_S_threshold))
{
std::__insertion_sort(__first, __first + int(_S_threshold), __comp);
std::__unguarded_insertion_sort(__first + int(_S_threshold), __last,__comp);
}
else
std::__insertion_sort(__first, __last, __comp);
}
-
检查排序范围大小:首先,算法检查要排序的元素数量是否大于预设的阈值
_S_threshold。这个阈值是基于性能考量设定的,目的是在较小的数据集上使用插入排序,而在较大的数据集上采用更复杂的排序算法。 -
条件分支:
-
如果范围内的元素数量不大于阈值,则直接对整个范围
[__first, __last)使用std::__insertion_sort进行插入排序. -
如果范围内的元素数量大于阈值,则执行两步操作:
-
局部插入排序:使用
std::__insertion_sort对范围[__first, __first + _S_threshold)内的元素进行插入排序。这意味着只对开始的部分元素进行排序,以快速地将这部分数据整理成有序状态。 -
无保护插入排序:随后,对剩余的元素(即
[__first + _S_threshold, __last)范围内的元素)使用std::__unguarded_insertion_sort进行插入排序。这个"无保护"版本的插入排序假设前面的元素已经被排序,因此可以省略某些边界检查,从而提高效率。
-
-
综合来说,sort 算法的实现细节如下:
-
初始时使用快速排序。
-
当递归深度达到阈值时切换到堆排序。
-
当待排序序列的长度变得较小时切换到插入排序。
-
根据需要排序的元素数量是否大于阈值,决定用那种插入排序或者混合。
本文分析了C++标准库中的sort函数源码,主要涉及__sort的实现,包括快速排序、混合策略(当递归深度达到阈值时切换到堆排序,小范围用插入排序)以及__introsort_loop和__final_insertion_sort的具体功能。
2153

被折叠的 条评论
为什么被折叠?



