# 堆操作汇总

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)

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)
++__parent;
}
return __n;
}


### is_heap()(C++11)

template<typename _RandomAccessIterator>
bool is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last);

template<typename _RandomAccessIterator, typename _Compare>
bool is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,_Compare __comp)


//它的实现交给了is_heap_until()来实现
template<typename _RandomAccessIterator>
inline bool is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
//判断最大长度堆的后一个元素是否与__last相等
return std::is_heap_until(__first, __last) == __last;
}

//它的实现交给了__is_heap_until()来实现
template<typename _RandomAccessIterator, typename _Compare>
inline bool is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,_Compare __comp)
{
//获取当前序列长度
const auto __dist = std::distance(__first, __last);
//重命名仿函数类型
typedef __decltype(__comp) _Cmp;
//_GLIBCXX_MOVE:  #define _GLIBCXX_MOVE(__val) std::move(__val)
//右值引用，构造仿函数
__gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
//判断最大堆长度是否与当前序列相等
return std::__is_heap_until(__first, __dist, __cmp) == _dist;
}


### push_heap()

template< class RandomIt >
void push_heap( RandomIt first, RandomIt last );

template< class RandomIt, class Compare >
void push_heap( RandomIt first, RandomIt last,Compare comp);


template<typename _RandomAccessIterator>
void push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
//萃取类型
typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type _DistanceType;
//定义比较仿函数
__gnu_cxx::__ops::_Iter_less_val __comp;

_ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
std::__push_heap(__first, _DistanceType((__last - __first) - 1),_DistanceType(0), _GLIBCXX_MOVE(__value), __comp);
}

template<typename _RandomAccessIterator, typename _Distance, typename _Tp,typename _Compare>
void __push_heap(_RandomAccessIterator __first,_Distance __holeIndex, _Distance __topIndex, _Tp __value, _Compare& __comp)
{
//这是可能含有叶节点的最后一个位置，之前的节点全是包含叶节点
_Distance __parent = (__holeIndex - 1) / 2;
//做两个判断，一是__holeIndexh还在已知堆里，以及不满足堆性质在，则再向上寻找__value正确的位置，知道找到为止
while (__holeIndex > __topIndex && __comp(__first + __parent, __value))
{
//将不满足性质的父节点往子节点放
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
//到父节点上去寻找是否满足堆性质
__holeIndex = __parent;
//父节点的父节点
__parent = (__holeIndex - 1) / 2;
}
//找到正确的位置后
*(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
}


### make_heap()

template<typename _RandomAccessIterator>
inline void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
__gnu_cxx::__ops::_Iter_less_iter __comp;
std::__make_heap(__first, __last, __comp);
}

template<typename _RandomAccessIterator, typename _Compare>
inline void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,_Compare __comp)
{
typedef __decltype(__comp) _Cmp;
__gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
std::__make_heap(__first, __last, __cmp);
}

template<typename _RandomAccessIterator, typename _Compare>
void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,_Compare& __comp)
{
//萃取类型
typedef typename iterator_traits<_RandomAccessIterator>::value_type  _ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type _DistanceType;

//当序列长度不足2时，直接返回
if (__last - __first < 2)
return;
//计算所建堆长堆
const _DistanceType __len = __last - __first;
//这是可能含有叶节点的最后一个位置，之前的节点全都包含叶节点
_DistanceType __parent = (__len - 2) / 2;

//从含有叶节点的第一个节点开始建堆
while (true)
{
//_GLIBCXX_MOVE:  #define _GLIBCXX_MOVE(__val) std::move(__val)
//提出父节点，从父节点开始调整以它为根节点的树成为堆
_ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),__comp);
if (__parent == 0)
return;
__parent--;
}
}
//调整堆，以__holeIndex为根节点的树，除去以__holeIndex节点为堆，
template<typename _RandomAccessIterator, typename _Distance,typename _Tp, typename _Compare>
void __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,_Distance __len, _Tp __value, _Compare __comp)
{
//调整堆的过程可以看做是，把除__holeIndex的所有节点调整为一个堆，然后把这个值push进堆中
//这是根节点
const _Distance __topIndex = __holeIndex;
//孩子节点，还未计算，保存的是根节点
_Distance __secondChild = __holeIndex;

//拥有两个叶节点的处理方式
while (__secondChild < (__len - 1) / 2)
{
//计算第二个孩子节点
__secondChild = 2 * (__secondChild + 1);
//在子节点上挑一个最小/大的节点，作为跟节点
if (__comp(__first + __secondChild,__first + (__secondChild - 1)))
__secondChild--;
//将__holeIndex下放，直到为叶节点为止
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
__holeIndex = __secondChild;
}

//如果只有一个叶节点
if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
{
__secondChild = 2 * (__secondChild + 1);
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + (__secondChild - 1)));
__holeIndex = __secondChild - 1;
}
//最终除__value以外，已经变成堆了，再将__value压入堆中
__decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp))) __cmp(_GLIBCXX_MOVE(__comp));
std::__push_heap(__first, __holeIndex, __topIndex,_GLIBCXX_MOVE(__value), __cmp);
}


### pop_heap()

template<typename _RandomAccessIterator>
inline void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last);

template<typename _RandomAccessIterator, typename _Compare>
inline void pop_heap(_RandomAccessIterator __first,_RandomAccessIterator __last, _Compare __comp);


template<typename _RandomAccessIterator>
inline void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
if (__last - __first > 1)
{
--__last;
__gnu_cxx::__ops::_Iter_less_iter __comp;
//注意，如若长度大于1，__last指向后一个元素，__last-__first表示原来的长度减一
std::__pop_heap(__first, __last, __last, __comp);
}
}

template<typename _RandomAccessIterator, typename _Compare>
inline void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,_RandomAccessIterator __result, _Compare& __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type _DistanceType;
//获取最后一个元素值，用它参与建堆
_ValueType __value = _GLIBCXX_MOVE(*__result);
//将顶部元素，放入最后一个位置
*__result = _GLIBCXX_MOVE(*__first);
//这里的长度比传入时少1。这里表示把除最后一个元素外，调整堆，并且最后一个元素，已经被顶部元素赋值。
std::__adjust_heap(__first, _DistanceType(0),_DistanceType(__last - __first),_GLIBCXX_MOVE(__value), __comp);
}


### sort_heap()

template<typename _RandomAccessIterator>
inline void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last);

template<typename _RandomAccessIterator, typename _Compare>
inline void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,_Compare __comp);


template<typename _RandomAccessIterator>
inline void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
__gnu_cxx::__ops::_Iter_less_iter __comp;
std::__sort_heap(__first, __last, __comp);
}

//不断将堆顶元素置于尾部
template<typename _RandomAccessIterator, typename _Compare>
void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,_Compare& __comp)
{
while (__last - __first > 1)
{
--__last;
std::__pop_heap(__first, __last, __last, __comp);
}
}



## 优先队列

STL中的优先队列，需要指定一个容器（支持随机访问），以及比较函数。它成员函数的具体实现，都是由之前介绍的堆操作完成的。

template<
class T,//数据类型
class Container = std::vector<T>,//容器类型
class Compare = std::less<typename Container::value_type>//比较函数
> class priority_queue;


public成员函数
top 访问堆顶元素。函数声明：const_reference top() const;
empty 检查容器是否为空。函数声明：bool empty() const；
size 返回容器元素。函数声明：size_type size() const；
push 压入新元素进堆。
void push( const value_type& value );
void push( value_type&& value );
emplace(C++11) 压入新元素进堆。

emplate< class… Args >
void emplace( Args&&… args );
pop 将栈顶元素弹出，先放到尾部，在pop_back()。
void pop();
swap 交换内容。
void swap(priority_queue& __pq);

template<typename _Tp, typename _Sequence = vector<_Tp>,typename _Compare  = less<typename _Sequence::value_type> >
class priority_queue
{

public:
//类型定义
typedef typename	_Sequence::value_type		value_type;
typedef typename	_Sequence::reference		 reference;
typedef typename	_Sequence::const_reference	   const_reference;
typedef typename	_Sequence::size_type		 size_type;
typedef				_Sequence			    container_type;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 2684. priority_queue lacking comparator typedef
typedef	       _Compare				    value_compare;

protected:
//  数据成员
_Sequence  c;
_Compare   comp;

public:
//可以从下面的代码中获悉，无论是构造函数，还是一般操作，都通过序列的操作，或者算法中堆操作实现。
explicit priority_queue(const _Compare& __x, const _Sequence& __s): c(__s), comp(__x)
{ std::make_heap(c.begin(), c.end(), comp); }

explicit priority_queue(const _Compare& __x, _Sequence&& __s = _Sequence()): c(std::move(__s)), comp(__x)
{ std::make_heap(c.begin(), c.end(), comp); }

template<typename _InputIterator>
priority_queue(_InputIterator __first, _InputIterator __last,const _Compare& __x,const _Sequence& __s)
: c(__s), comp(__x)
{
__glibcxx_requires_valid_range(__first, __last);
c.insert(c.end(), __first, __last);
std::make_heap(c.begin(), c.end(), comp);
}

template<typename _InputIterator>
priority_queue(_InputIterator __first, _InputIterator __last,const _Compare& __x = _Compare(),
_Sequence&& __s = _Sequence())
: c(std::move(__s)), comp(__x)
{
__glibcxx_requires_valid_range(__first, __last);
c.insert(c.end(), __first, __last);
std::make_heap(c.begin(), c.end(), comp);
}

/**
*  Returns true if the %queue is empty.
*/
bool empty() const
{ return c.empty(); }
/**  Returns the number of elements in the %queue.  */
size_type size() const
{ return c.size(); }

/**
*  Returns a read-only (constant) reference to the data at the first
*  element of the %queue.
*/
const_reference top() const
{
__glibcxx_requires_nonempty();
return c.front();
}

void push(const value_type& __x)
{
c.push_back(__x);
std::push_heap(c.begin(), c.end(), comp);
}

void pop()
{
__glibcxx_requires_nonempty();
std::pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}

template<typename... _Args>
void emplace(_Args&&... __args)
{
c.emplace_back(std::forward<_Args>(__args)...);
std::push_heap(c.begin(), c.end(), comp);
}

void swap(priority_queue& __pq)
{
using std::swap;
swap(c, __pq.c);
swap(comp, __pq.comp);
}
};


## 使用示例

/*
STL中的堆操作以及优先队列的使用
*/
#include <algorithm>
#include <vector>
#include <queue>
#include <iostream>
#define _GLIBCXX_DEBUG
using namespace std;

template<typename T>
inline void showContainer(T a){
for(auto i : a){
cout<<i<<",";
}
cout<<endl;
}
int main(){
vector<int> v1 = {21,42,36,4,57,6,7,77,99};

cout<<"v1是否为堆："<<is_heap(v1.begin(),v1.end())<<endl;
cout<<"v1堆最大长度："<<distance(v1.begin(),is_heap_until(v1.begin(),v1.end()))<<endl;
//默认为大根堆
//[v1.begin(),v1.end()-1)之间建堆
make_heap(v1.begin(),v1.end()-1);
showContainer(v1);
//压入尾元素
push_heap(v1.begin(),v1.end());
showContainer(v1);
//将栈顶元素放入最后一个位置
pop_heap(v1.begin(),v1.end());
showContainer(v1);
//排序，默认大根堆，从小到大排序
sort_heap(v1.begin(),v1.end()-1);
showContainer(v1);

v1 = {21,42,36,4,57,6,7,77,99};
//小根堆,指定比较函数
make_heap(v1.begin(),v1.end(),greater<int>());
showContainer(v1);

//排序，从大到小排序
sort_heap(v1.begin(),v1.end(),greater<int>());
showContainer(v1);

//优先队列,默认最大堆，大根堆，最大优先
//v1 = {21,42,36,4,57,6,7,77,99};
v1 = {21,42,36,4,57,6,7,77,99};
priority_queue<int> v2(v1.begin(),v1.end());
cout<<v2.top()<<endl;
while(!v2.empty()){
cout<<v2.top()<<",";
v2.pop();
}

return 0;
}
/**输出如下
v1是否为堆：0
v1堆最大长度：1
77,57,36,42,21,6,7,4,99,
99,77,36,57,21,6,7,4,42,
77,57,36,42,21,6,7,4,99,
4,6,7,21,36,42,57,77,99,
4,21,6,42,57,36,7,77,99,
99,77,57,42,36,21,7,6,4,
99
99,77,57,42,36,21,7,6,4,
**/


# Reference

1.https://en.cppreference.com/w/cpp/algorithm

2.GNU7.2.0C++标准库源代码

06-01 292

07-11 1126

12-30 743

10-15 3106

08-09 1844

09-01 497

04-08 223

10-25 17

07-25 915

09-22 97

#### STL源码 阅读笔记（一） 迭代器头文件stl_iterator_base_types.h

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。