您的位置:首页 > 其它

泛型算法系列37:堆算法

2009-08-24 14:03 155 查看
#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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: