泛型算法系列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);
相关文章推荐
- [算法系列] 费式数列
- 白话经典算法系列之七 堆与堆排序
- 白话经典算法系列之六 快速排序 快速搞定(转)
- SSE图像算法优化系列一:一段BGR2Y的SIMD代码解析。
- 白话经典算法系列之一 冒泡排序的三种实现(转)
- C语言之基本算法37—数组最大值及其位置
- 白话经典算法系列之八 MoreWindows白话经典算法之七大排序总结篇
- 集群系列二(LVS的算法)
- 全文检索、数据挖掘、推荐引擎系列7---条目相似度算法
- 白话经典算法系列之二 直接插入排序的三种实现
- 深度学习DeepLearning.ai系列课程学习总结:12. 优化算法实战
- 鸡啄米:C++编程入门系列之七(算法的基本控制结构之循环结构)
- 算法系列15天速成——第二天 七大经典排序【中】
- 算法系列之十二:多边形区域填充算法--几种边标志填充算法
- 算法系列15天速成——第十天 栈
- 算法系列15天速成——第十四天 图【上】
- 解密SVM系列(三):SMO算法原理与实战求解
- C#数据结构和算法学习系列二----泛型编程
- 每天学习一算法系列(6) (输入一个整数和一棵二元树,从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径,打印出和与输入整数相等的所有路径)
- 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结