STL算法与数据结构—堆有关操作以及优先队列
本文将STL中的堆有关算法,做了些整理,以及扒出了它的源代码(去除了许多不必要的版本控制代码),并简单的注释了他们的大概运行过程。除示例代码以外,其余代码,均可以在GNU7.2.0中找到。
堆操作汇总
Heap operations,Defined in header <algorithm> |
|
---|---|
is_heap(C++11) | checks if the given range is a max heap (function template) |
is_heap_until(C++11) | finds the largest subrange that is a max heap (function template) |
make_heap | creates a max heap out of a range of elements (function template) |
push_heap | adds an element to a max heap (function template) |
pop_heap | removes the largest element from a max heap (function template) |
sort_heap | turns a max heap into a range of elements sorted in ascending order (function template) |
is_heap_until()(C++11)
先介绍这个函数,因为之后的函数有调用它。如前表所述,这个函数返回满足堆性质的最大子范围(从传入的first开始的范围),并且返回一个迭代器(first到这个迭代器是一个堆,左闭右开区间)。
主要有两个函数原型,一个是不带比较仿函数的,另一个是需要自定义比较仿函数的。另外他们都需要传入随机访问迭代器。并且他们的输出是随机访问迭代器。
template<typename _RandomAccessIterator>
_RandomAccessIterator is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last);
template<typename _RandomAccessIterator, typename _Compare>
_RandomAccessIterator is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,_Compare __comp)
具体实现:
//定义于stl_heap.h
//为了方便理解,把concept requirements那部分代码删去
//返回类型是随机访问迭代器
template<typename _RandomAccessIterator>
inline _RandomAccessIterator is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
//这里在定义一个仿函数,就是一个比较函数,访问迭代器元素并比较大小,其实现见之后代码
__gnu_cxx::__ops::_Iter_less_iter __comp;
//返回的是_first+最大堆长度,调用了__is_heap_until来返回最大堆长度
return __first +
std::__is_heap_until(__first, std::distance(__first, __last), __comp);
}
template<typename _RandomAccessIterator, typename _Compare>
inline _RandomAccessIterator is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,_Compare __comp)
{
//重命名_Compare,__decltype(__comp)返回了_comp的类型
typedef __decltype(__comp) _Cmp;
//定义比较仿函数
__gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
//返回的是_first+最大堆长度,调用了__is_heap_until来返回最大堆长度
//distance是STL中计算两个迭代器的长度函数(左闭右开)。
return __first + std::__is_heap_until(__first, std::distance(__first, __last), __cmp);
}
//_it1的元素如若小于_it2的元素,则返回true,结合__is_heap_until的实现,可知默认在判断是否为大根堆
struct _Iter_less_iter
{
template<typename _Iterator1, typename _Iterator2>
bool operator()(_Iterator1 __it1, _Iterator2 __it2) const
{ return *__it1 < *__it2; }
};
//来看看__is_heap_until的实现
template<typename _RandomAccessIterator, typename _Distance,typename _Compare>
_Distance __is_heap_until(_RandomAccessIterator __first, _Distance __n,_Compare& __comp)
{
//从第一个元素开始验证
_Distance __parent = 0;
for (_Distance __child = 1; __child < __n; ++__child)
{
//判断父节点与子节点是否满足堆的性质,不满足则返回当前长度
if (__comp(__first + __parent, __first + __child))
return __child;
//如为偶数,__parent往后遍历,为偶数时,验证完两个孩子了,所以该往后遍历了
if ((__child & 1) == 0)