堆知识总结
来源:互联网 发布:terminal mac 编辑:程序博客网 时间:2024/06/06 18:49
堆是一种完全二叉树,堆结构的二叉树存储方式分为大堆和小堆。
大堆:每个父节点都大于孩子节点
小堆:每个父节点都小于孩子节点
创建一个大堆:向下调整算法
思路:我们知道堆均是完全二叉树,因此一个父节点的子节点即child = parent*2+1;因此在向下调整算法中从根节点开始逐一与它的孩子进行比较,每次保证一棵树最大数据是根节点。
例如:int a [] = {10,11, 13, 12, 16, 18, 15, 17, 14, 19};
用完全二叉树表示:
Heap(T* array, size_t sz) //大堆{ for (int i = 0; i < sz;++i) { _array.push_back(array[i]); } for (int j = (_array.size()-1) / 2; j>=0; --j) { _Adjustdown(j); }}void _Adjustdown(int root) //向下调整算法{ size_t parent = root; size_t child = parent * 2 + 1; while (parent < _array.size()) { if ((child+1)<(_array.size())&&_array[child+1] > _array[child]) { ++child; } if ((child<_array.size())&&_array[child] > _array[parent]) { swap(_array[child], _array[parent]); parent = child; //继续向下调整 child = parent * 2 + 1; } else { break; } }}
同理,我们创建一个小堆,使用向上调整算法:
例如:int a [] = {10,11, 13, 12, 16, 18, 15, 17, 14, 19};
将其转化为小堆模式代码:
void _AdjustUp(int root){ size_t parent = root; size_t child = parent * 2 + 1; while (parent < _array.size()) { if ((child + 1)<(_array.size()) && _array[child + 1] < _array[child]) { ++child; } if ((child<_array.size()) && _array[child] < _array[parent]) { swap(_array[child], _array[parent]); parent = child; //继续向下调整 child = parent * 2 + 1; } else { break; } }}
转化后为:
堆的删除:堆一般进行pop()操作,删除堆顶元素:
思路:如果我们直接进行删除数组第一个元素_array[0],那么还必须进行堆排序操作,时间复杂度较大,但是我们换个思路,要删除第一个数,由于第一个数变化对整个数组均影响,因此我们可以先把第一个和最后一个调换位置,然后删除最后一个,最进行向下调整算法(大堆)或向上调整算法(小堆)即可。
代码如下:
void Pop(){ assert(!_array.empty()); swap(_array[0], _array[_array.size() - 1]); _array.pop_back(); _Adjustdown(0);}
堆的插入:插入算法就是把一个节点插入到堆的最后,然后进行向上或向下调整算法
void Push(const T& x){ _array.push_back(x); _Adjustdown(0);}
但是我们发现在进行大堆或小堆操作时,代码差不多都相同,只有少数几个判断大小的符号不同,这样也不易维护,因此增加代码简洁型型=性,我们可采用仿函数进行优化。
通过仿函数,我们只需要传入一个模板参数,然后通过创建的对象就可以实现控制是大堆还是小堆。
源代码:
//需要小堆template <class T>struct Less{ bool operator()(const T& x1, const T& x2) { return x1 < x2; }};//当需要大堆时template <class T>struct Greater{ bool operator ()(const T& a, const T& b) { return a > b; }};template<class T, class compare = Greater<T>>class Heap{public:Heap(){}Heap(T* array, size_t sz) //大堆{ for (size_t i = 0; i < sz;++i) { _array.push_back(array[i]); } for (int j = (_array.size()-1) / 2; j>=0; --j) { _Adjustdown(j); }}void Pop(){ assert(!_array.empty()); swap(_array[0], _array[_array.size() - 1]); _array.pop_back(); _Adjustdown(0);}void Push(const T& x){ _array.push_back(x); _Adjustdown(0);}protected:void _Adjustdown(int root) //向下调整算法{ size_t parent = root; size_t child = parent * 2 + 1; while (parent <_array.size()) { if ((child + 1)<(_array.size()) && com(_array[child + 1] , _array[child])) { ++child; } if ((child<_array.size())&&com(_array[child] , _array[parent])) { swap(_array[child], _array[parent]); parent = child; //继续向下调整 child = parent * 2 + 1; } else { break; } }}private: vector<T> _array; Compare<T> com;};int main(){ int a[] = { 10, 11, 13, 12, 16, 18, 15, 17, 14, 19 }; Heap<int,Less<int>> b(a, sizeof(a)/sizeof(int)); b.Pop(); b.Push(1); system("pause"); return 0;}
堆的一些简单应用:
设计优先级队列:
template<typename T, typename Compare = Greater<T>>class PriorityQueue{public: PriorityQueue(T* a, size_t size) :_h(a, size) {} void Push(const T& d) { _h.Push(d); } void Pop() { _h.pop(); } size_t Size() { return _h.Size(); } const T& Top() { return _h.Top(); } bool empty() { return _h.empty(); }protected: Heap<T, Compare> _h;};
阅读全文
0 0
- 堆知识总结
- java 自我知识总结(六) 栈 堆 队列
- 堆的相关知识
- 堆的相关知识
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 知识总结
- 18_switch语句_基本用法_case穿透现象
- unicode为12288字符
- java客户端操作fastdfs集群
- 【Angular2】You have to be inside an angular-cli project in order to use the generate command
- web的Seo搜索优化
- 堆知识总结
- LeetCode 43. Multiply Strings
- 函数的高阶特性——Python学习笔记04
- 使用Travis CI自动打包APK,并发布到fir
- JSplitPane 监听分割位置
- 用Swift 给tableView加载xib创建的tableHeaderView时不显示问题
- Android问题:com.android.builder.packaging.DuplicateFileException
- eq相等 ne、neq不相等, gt大于, lt小于 gte、ge大于等于 lte、le 小于等于 not非 mod求模 等
- 在逻辑学中,SAP,SEP,SIP,SOP,SaP,SeP分别是什么意思?