使用一个东西,不明白它的道理,不高明
——侯捷老师
1. is_heap()函数
判断一个序列是否能形成一个堆
1.1 函数声明
// defautl(1)
template
bool is_heap(RandomAccessIterator first, RandomAccessIterator last)
// custom(2)
template
bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
1.3 源码探究
通过查看源码,发现is_heap()内部调用的是is_heap_until()函数
template
inline bool
is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp)
{ return std::is_heap_until(__first, __last, __comp) == __last; }
1.3 示例程式
void test_is_heap() {
/**
// defautl(1)
template
bool is_heap(RandomAccessIterator first, RandomAccessIterator last)
// custom(2)
template
bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
*/
#include // std::cout
#include // std::is_heap, std::make_heap, std::pop_heap
#include // std::vector
std::vector foo {9,5,2,6,4,1,3,8,7};
if (!std::is_heap(foo.begin(),foo.end()))
std::make_heap(foo.begin(),foo.end());
std::cout << "Popping out elements:";
while (!foo.empty()) {
std::pop_heap(foo.begin(),foo.end()); // moves largest element to back
std::cout << ' ' << foo.back(); // prints back
foo.pop_back(); // pops element out of container
}
std::cout << '\n';
}
1.4 参考链接
http://www.cplusplus.com/reference/algorithm/is_heap/
2. is_heap_until()函数
返回第一个不满足堆的元素的迭代器位置
2.1 函数声明
// default(1)
template
RandomAccessIterator is_heap_until (RandomAccessIterator first, RandomAccessIterator last);
// custom(2)
template
RandomAccessIterator is_heap_until (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
2.2 源码探究
is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp) {
// concept requirements
__glibcxx_function_requires(_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_requires_valid_range(__first, __last);
return __first
+ std::__is_heap_until(__first, std::distance(__first, __last),
__gnu_cxx::__ops::__iter_comp_iter(__comp));
}
--------------------------分界线--------------------------
template
_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;
if ((__child & 1) == 0)
++__parent;
}
return __n;
}
2.3 示例程式
void test_is_heap_until() {
/**
// default(1)
template
RandomAccessIterator is_heap_until (RandomAccessIterator first,
RandomAccessIterator last);
// custom(2)
template
RandomAccessIterator is_heap_until (RandomAccessIterator first,
RandomAccessIterator last
Compare comp);
*/
std::vector foo {2,6,9,3,8,4,5,1,7};
std::sort(foo.begin(),foo.end());
std::reverse(foo.begin(),foo.end());
auto last = std::is_heap_until (foo.begin(),foo.end());
std::cout << "The " << (last-foo.begin()) << " first elements are a valid heap:";
for (auto it=foo.begin(); it!=last; ++it)
std::cout << ' ' << *it;
std::cout << '\n';
}
2.4 输出结果
3. make_heap()函数
构建一个堆,默认为大根堆;可以通过自定义的comp来构建小根堆。使用greater
3.1 函数声明
// default(1)
template
void make_heap(RandomAccessIterator first, RandomAccessIterator last)
// custom(2)
template
void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
3.2 源码探究
template
inline void
make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp)
{
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_requires_valid_range(__first, __last);
std::__make_heap(__first, __last,
__gnu_cxx::__ops::__iter_comp_iter(__comp));
}
---------------------------
template
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;
if (__last - __first < 2)
return;
const _DistanceType __len = __last - __first;
_DistanceType __parent = (__len - 2) / 2;
while (true)
{
_ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
__comp);
if (__parent == 0)
return;
__parent--;
}
}
3.3 示例程式
void test_make_heap() {
/**
// default(1)
template
void make_heap(RandomAccessIterator first, RandomAccessIterator last)
// custom(2)
template
void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
*/
// 默认构建大根堆
int myints[] = {10,20,30,5,15};
std::vector v(myints,myints+5);
std::make_heap (v.begin(),v.end());
std::cout << "initial max heap : " << v.front() << '\n';
std::pop_heap (v.begin(),v.end()); v.pop_back();
std::cout << "max heap after pop : " << v.front() << '\n';
v.push_back(99); std::push_heap (v.begin(),v.end());
std::cout << "max heap after push: " << v.front() << '\n';
std::sort_heap (v.begin(),v.end());
std::cout << "final sorted range :";
for (unsigned i=0; i());
for (auto &x : arr) {
cout << x << " ";
}
cout << endl;
}
3.4 输出结果
3.5 参考链接
http://www.cplusplus.com/reference/algorithm/make_heap/
https://www.cnblogs.com/deathmr/p/9015644.html
4. push_heap()函数
4.1 函数声明
// default(1)
template
viod push_heap(RandomAccessIterator first, RandomAccessIterator last)
// custom(2)
template
void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
注意事项:使用push_heap(f, l)的话,调用者需要确保[f, l-1)已经是一个堆. push_heap(f, l)仅仅会把*(l-1)插入到[f, l-1)这个区间形成的堆中,时间复杂度是O(logN).
4.2 源码探究
template
inline void
push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type
_DistanceType;
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_requires_valid_range(__first, __last);
__glibcxx_requires_heap_pred(__first, __last - 1, __comp);
_ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
std::__push_heap(__first, _DistanceType((__last - __first) - 1),
_DistanceType(0), _GLIBCXX_MOVE(__value),
__gnu_cxx::__ops::__iter_comp_val(__comp));
}
---------------------分界线----------------------
template
void
__push_heap(_RandomAccessIterator __first,
_Distance __holeIndex, _Distance __topIndex, _Tp __value,
_Compare __comp)
{
_Distance __parent = (__holeIndex - 1) / 2;
while (__holeIndex > __topIndex && __comp(__first + __parent, __value))
{
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
__holeIndex = __parent;
__parent = (__holeIndex - 1) / 2;
}
*(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
}
4.3 示例程式
void test_push_heap() {
/**
// default(1)
template
viod push_heap(RandomAccessIterator first, RandomAccessIterator last)
// custom(2)
template
void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
*/
int myints[] = {10, 20, 30, 5, 15};
std::vector v(myints, myints+5);
std::make_heap(v.begin(), v.end());
std::cout << "initial max heap: " << v.front() << endl;
std::pop_heap(v.begin(), v.end());
v.pop_back();
std::cout << "max heap after pop: " << v.front() << endl;
v.push_back(99);
std::push_heap(v.begin(), v.end());
std::cout << "max heap after push: " << v.front() << endl;
std::sort_heap(v.begin(), v.end());
std::cout << "final sorted range: ";
for (int i = 0; i < v.size(); i++) {
cout << " " << v[i];
}
cout << endl;
}
4.4 输出结果
5. pop_heap()函数
功能:将最大值移到位置last-1,[first, last-1)重新构建大根堆。
注意事项:在调用pop_heap时[first, last)已经是一个堆(使用相同的排序准则)
5.1 函数声明
// default(1)
template
void pop_heap(RandomAccessIterator first, RandomAccessIterator last);
// custom(2)
template
void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
5.2 源码探究
通过查看源码,发现函数调用过程是:
pop_heap()->std::__pop_heap()->__adjust_heap()->__push_heap()
pop_heap()函数:
template
inline void
pop_heap(_RandomAccessIterator __first,
_RandomAccessIterator __last, _Compare __comp)
{
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_requires_valid_range(__first, __last);
__glibcxx_requires_non_empty_range(__first, __last);
__glibcxx_requires_heap_pred(__first, __last, __comp);
if (__last - __first > 1)
{
--__last;
std::__pop_heap(__first, __last, __last,
__gnu_cxx::__ops::__iter_comp_iter(__comp));
}
}
std::__pop_heap()函数
template
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);
std::__adjust_heap(__first, _DistanceType(0),
_DistanceType(__last - __first),
_GLIBCXX_MOVE(__value), __comp);
}
__adjust_heap()函数
cpp
template
void
__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
_Distance __len, _Tp __value, _Compare __comp)
{
const _Distance __topIndex = __holeIndex;
_Distance __secondChild = __holeIndex;
while (__secondChild < (__len - 1) / 2)
{
__secondChild = 2 * (__secondChild + 1);
if (__comp(__first + __secondChild,
__first + (__secondChild - 1)))
__secondChild--;
*(__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;
}
std::__push_heap(__first, __holeIndex, __topIndex,
_GLIBCXX_MOVE(__value),
__gnu_cxx::__ops::__iter_comp_val(__comp));
__push_heap()函数
template
void
__push_heap(_RandomAccessIterator __first,
_Distance __holeIndex, _Distance __topIndex, _Tp __value,
_Compare __comp)
{
_Distance __parent = (__holeIndex - 1) / 2;
while (__holeIndex > __topIndex && __comp(__first + __parent, __value))
{
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
__holeIndex = __parent;
__parent = (__holeIndex - 1) / 2;
}
*(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
}
6. sort_heap()函数
功能:Sorts the elements in the heap range [first,last) into ascending order.
sort_heap即经典的堆排序算法,通过每次弹出堆顶直到堆为空,依次被弹出的元素就组成了有序的序列了。STL中的priority_queue即使用heap的这个特性来实现。使用sort_heap(f, l)处理过的区间因为已经有序,就不再是一个heap了。
6.1 函数声明
// default(1)
template
void pop_heap(RandomAccessIterator first, RandomAccessIterator last);
// custom(2)
template
void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
6.2 源码探究
通过看源码,发现函数调用过程是:
sort_heap()->__sort_heap()->__pop_heap->__adjust_heap->__push_heap
sort_heap()函数:
template
inline void
sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp)
{
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_requires_valid_range(__first, __last);
__glibcxx_requires_heap_pred(__first, __last, __comp);
std::__sort_heap(__first, __last,
__gnu_cxx::__ops::__iter_comp_iter(__comp));
}
__sort_heap()函数:
template
void
__sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp)
{
while (__last - __first > 1)
{
--__last;
std::__pop_heap(__first, __last, __last, __comp);
}
}
__pop_heap()函数:
template
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);
std::__adjust_heap(__first, _DistanceType(0),
_DistanceType(__last - __first),
_GLIBCXX_MOVE(__value), __comp);
}
adjust_heap()函数
template
void
__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
_Distance __len, _Tp __value, _Compare __comp)
{
const _Distance __topIndex = __holeIndex;
_Distance __secondChild = __holeIndex;
while (__secondChild < (__len - 1) / 2)
{
__secondChild = 2 * (__secondChild + 1);
if (__comp(__first + __secondChild,
__first + (__secondChild - 1)))
__secondChild--;
*(__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;
}
std::__push_heap(__first, __holeIndex, __topIndex,
_GLIBCXX_MOVE(__value),
__gnu_cxx::__ops::__iter_comp_val(__comp));
}
__push_heap()函数:
template
void
__push_heap(_RandomAccessIterator __first,
_Distance __holeIndex, _Distance __topIndex, _Tp __value,
_Compare __comp)
{
_Distance __parent = (__holeIndex - 1) / 2;
while (__holeIndex > __topIndex && __comp(__first + __parent, __value))
{
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
__holeIndex = __parent;
__parent = (__holeIndex - 1) / 2;
}
*(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
}