模板函数sort_heap具有如下两个版本
template<class _RanIt> void sort_heap(_RanIt _First, _RanIt _Last);
template<class _RanIt, class _Pr> void sort_heap(_RanIt _First, _RanIt _Last, _Pr _Pred);
其功能是完成区间 [_First, _Last) 内元素的堆排序,第一个版本采用小于操作符(operator<),
第二个版本采用一个二元谓词(binary predicate)。
下面将以第一个版本的算法源代码进行注释说明
template<class _RanIt> inline void sort_heap(_RanIt _First, _RanIt _Last) { // order heap by repeatedly popping, using operator< _DEBUG_HEAP(_First, _Last); // 通过重复取出第一个元素完成堆排序 _Sort_heap(_CHECKED_BASE(_First), _CHECKED_BASE(_Last)); }
_Sort_heap函数
template<class _RanIt> inline void _Sort_heap(_RanIt _First, _RanIt _Last) { // order heap by repeatedly popping, using operator< _DEBUG_RANGE(_First, _Last); _DEBUG_HEAP(_First, _Last); // 通过重复取出第一个元素完成堆排序 for (; 1 < _Last - _First; --_Last) std::pop_heap(_First, _Last); }
pop_heap函数
template<class _RanIt> inline void pop_heap(_RanIt _First, _RanIt _Last) { // pop *_First to *(_Last - 1) and reheap, using operator< _DEBUG_RANGE(_First, _Last); _DEBUG_HEAP(_First, _Last); if (1 < _Last - _First) // 将第一个元素放在末尾 _Pop_heap_0(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Val_type(_First)); }
_Pop_heap_0函数
template<class _RanIt, class _Ty> inline void _Pop_heap_0(_RanIt _First, _RanIt _Last, _Ty *) { // pop *_First to *(_Last - 1) and reheap, using operator< // 将第一个元素放在末尾,注意这里将原末尾元素以参数值传递形式传入 _Pop_heap(_First, _Last - 1, _Last - 1, _Ty(*(_Last - 1)), _Dist_type(_First)); }
_Pop_heap函数
template<class _RanIt, class _Diff, class _Ty> inline void _Pop_heap(_RanIt _First, _RanIt _Last, _RanIt _Dest, _Ty _Val, _Diff *) { // pop *_First to *_Dest and reheap, using operator< // 更新末值 *_Dest = *_First; // 对末值前的区间元素进行堆调整,_Val 为原末值 std::_Adjust_heap(_First, _Diff(0), _Diff(_Last - _First), _Val); }
_Adjust_heap函数
template<class _RanIt, class _Diff, class _Ty> inline void _Adjust_heap(_RanIt _First, _Diff _Hole, _Diff _Bottom, _Ty _Val) { // percolate _Hole to _Bottom, then push _Val, using operator< _Diff _Top = _Hole; _Diff _Idx = 2 * _Hole + 2; for (; _Idx < _Bottom; _Idx = 2 * _Idx + 2) { // move _Hole down to larger child // 求取左右孩子中的值较大者 if (_DEBUG_LT(*(_First + _Idx), *(_First + (_Idx - 1)))) --_Idx; // 这里使用了逗号表达式 *(_First + _Hole) = *(_First + _Idx), _Hole = _Idx; } if (_Idx == _Bottom) { // only child at bottom, move _Hole down to it *(_First + _Hole) = *(_First + (_Bottom - 1)); _Hole = _Bottom - 1; } std::_Push_heap(_First, _Hole, _Top, _Val); }
_Push_heap函数
template<class _RanIt, class _Diff, class _Ty> inline void _Push_heap(_RanIt _First, _Diff _Hole, _Diff _Top, _Ty _Val) { // percolate _Hole to _Top or where _Val belongs, using operator< // 将给定值 _Val 放入正确的节点中 for (_Diff _Idx = (_Hole - 1) / 2; _Top < _Hole && _DEBUG_LT(*(_First + _Idx), _Val); _Idx = (_Hole - 1) / 2) { // move _Hole up to parent // 当前节点值小于 _Val,则上溯 *(_First + _Hole) = *(_First + _Idx); _Hole = _Idx; } // 找到不小于 _Val 的节点 *(_First + _Hole) = _Val; // drop _Val into final hole }
至此已完成堆排序,不过使用sort_heap需要注意下面三点
(1)首先把建堆,即调用make_heap
(2)由于对原末值的保存是通过参数值传递,如_Pop_heap及以后的函数中的参数 _Val,因而对于某些复杂的自定义类型将不适用,
即expensive type
(3)sort_heap的时间复杂度为O(NlogN)
代码版本来源于Microsoft Visual Studio 2008 安装包中<algorithm>文件,版权归原作者所有!