泛型算法系列37:堆算法

#include <algorithm> #include <vector> #include <iostream> #include <functional> using namespace std; template <class Type> void print_elements( Type elem ) { cout << elem << " "; } /************************************************************************/ /* */ template<class _RanIt> inline void my_Make_heap(_RanIt _First, _RanIt _Last) { // make nontrivial [_First, _Last) into a heap, using operator< typedef iterator_traits<_RanIt>::difference_type _Diff; typedef iterator_traits<_RanIt>::value_type _Ty; _Diff _Bottom = _Last - _First; for (_Diff _Hole = _Bottom / 2; 0 < _Hole; ) { // reheap top half, bottom to top --_Hole; my_Adjust_heap(_First, _Hole, _Bottom, _Ty(*(_First + _Hole))); } } template<class _RanIt, class _Diff, class _Ty> inline void my_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); } 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< for (_Diff _Idx = (_Hole - 1) / 2; _Top < _Hole && _DEBUG_LT(*(_First + _Idx), _Val); _Idx = (_Hole - 1) / 2) { // move _Hole up to parent *(_First + _Hole) = *(_First + _Idx); _Hole = _Idx; } *(_First + _Hole) = _Val; // drop _Val into final hole } template<class _RanIt, class _Ty> inline void my_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)); } template<class _RanIt> inline void my_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) my_Pop_heap_0(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Val_type(_First)); } template<class _RanIt> inline void my_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); } /************************************************************************/ int main() { int ia[] = {29,23,20,22,17,15,26,51,19,12,35,40 }; vector< int > vec( ia, ia + 12 ); // generates: 51 35 40 23 29 20 26 22 19 12 17 15 my_Make_heap( &ia[0], &ia[12] ); void (*pfi)( int ) = print_elements; for_each( ia, ia + 12, pfi ); cout << "/n/n"; // generates: 12 17 15 19 23 20 26 51 22 29 35 40 // a min-heap: root is smallest element make_heap( vec.begin(), vec.end(), greater<int>() ); for_each( vec.begin(), vec.end(), pfi ); cout << "/n/n"; // generates: 12 15 17 19 20 22 23 26 29 35 40 51 sort_heap( ia, ia + 12 ); for_each( ia, ia + 12, pfi ); cout << "/n/n"; // add an additional, new smallest element: vec.push_back( 8 ); // generates: 8 17 12 19 23 15 26 51 22 29 35 40 20 // should place newest smallest element at root push_heap( vec.begin(), vec.end( ), greater<int>() ); for_each( vec.begin(), vec.end(), pfi ); cout << "/n/n"; // generates: 12 17 15 19 23 20 26 51 22 29 35 40 8 // should replace smallest element with second smallest pop_heap( vec.begin(), vec.end(), greater<int>() ); for_each( vec.begin(), vec.end(), pfi ); cout << "/n/n"; return 0; }

1。概念:堆是一种特殊的二叉树,具备以下两种性质
1)每个节点的值都大于(或者都小于,称为最小堆)其子节点的值
2)树是完全平衡的,并且最后一层的树叶都在最左边
这样就定义了一个最大堆。

2。堆可以用一个数组表示,有如下性质:
heap[i]>=heap[2*i+1]  其中0<=i<=(n-1)/2
heap[i]>=heap[2*i+2]  其中0<=i<=(n-2)/2

 

3.

// push_heap为向堆中添加一个新的元素, 调用这个算法的前提是[First, Last)之间的元素满足堆的条件
// 新加入的元素为Last
void    push_heap(int* pFirst, int* pLast);

// pop_heap为从堆中删除一个元素, 调用这个算法的前提是[First, Last)之间的元素满足堆的条件
// 被删除的元素被放置到Last - 1位置,由于这里是max-heap,所以被删除的元素是这个序列中最大的元素
void    pop_heap(int* pFirst, int* pLast);

// make_heap将序列[First, Last)中的元素按照堆的性质进行重组
void    make_heap(int* pFirst, int* pLast);

// 对堆进行排序, 调用这个函数可以成功排序的前提是[pFirst, pLast)中的元素符合堆的性质
void    sort_heap(int* pFirst, int* pLast);

你可能感兴趣的:(泛型算法系列37:堆算法)