堆
1.概念
堆是一种完全二叉树(除了最底层,其它层都必须填满,最后一层可以从左到右填满),堆的每一个节点都有一个值。
数据结构里的堆是由一些按照某种优先级来组织成的队列,所以堆又叫做优先队列,在STL中可以用priority_queue实现。
2.分类
堆可以分为最大堆和最小堆:
最大堆:每个父节点都大于各孩子节点
最小堆:每个父节点都小于各孩子节点
3.存储和性质
堆是一棵完全二叉树,所以使用数组可以高效的存储数据。
性质:
- 对于一个非根节点的节点 i 来说,如果它的下标为 k,那么它的父节点的下标为 (k -1)/2,子节点的下标为2 *k +1和2 *k + 2
- 每个结点的左子树和右子树都是一个二叉堆
4.堆的实现
现有数组 int* a={10,5,7,12,13,11,20,25,14,30};
根据这个数组建出一个带值的完全二叉树。
现在我们要使这个完全二叉树变成最大堆,就是让整棵树中的双亲节点都大于孩子节点。所以我们要从叶子结点开始调整,直到调整到根节点结束。
template<class T> struct Less { bool operator()(const T& a,const T& b) { return a<b; } }; template<class T> struct Greater { bool operator()(const T& a,const T& b) { return a>b; } }; template<typename T,class com = Greater<int>> class Heap { public: //构造函数 Heap(){} //建堆 Heap(T* a, size_t n) :_a(a,a+n) { for (int i = (_a.size()-2)/2; i>=0; i--) { _Adjustdown(i); } } //尾插 void Push(const T& x) { _a.push_back(x); _Adjustup(_a.size()-1); } //尾删 void Pop() { swap(_a[0],_a[_a.size()-1]); _a.pop_back(); _Adjustdown(0); } //求堆里元素的个数 size_t Size() { return _a.size(); } //求堆顶的元素 T& Top() { return _a[0]; } //判断堆是否为空 bool Empty() { return _a.size()==0; } protected: void _Adjustdown(int root) {//下调 int parent = root; int child = parent*2+1; while (child<_a.size()) { //找左右孩子中值最大的 if (child+1<_a.size() && com()(_a[child+1],_a[child])) { ++child; } //将孩子和父母做比较 if (com()(_a[child],_a[parent])) { swap(_a[child],_a[parent]); parent = child; child = parent*2+1; } else { break; } } } //上调 void _Adjustup(int i) { //Compare com; int child = i; int parent = (i-1)/2; while (child >= 0) { if (com()(_a[child] , _a[parent])) { swap(_a[child],_a[parent]); child = parent; parent = (parent-1)/2; } else { break; } } } protected: vector<T> _a; }; template<class T,class com = Greater<int>> class PriorityQueue { public: //构造函数 PriorityQueue() {} void Push_Back(const T& x) { _hp.Push(x); } void Pop_Front() { _hp.Pop(); } size_t PQ_Size() { return _hp.Size(); } T& PQ_Top() { return _hp.Top(); } bool PQ_Empty() { return _hp.Empty(); } protected: Heap<T,com> _hp; };