堆是形如下图的二叉树
堆的最重要的性质,就是儿子的值一定不小于父亲的值。树的节点从上到下,从左到右的顺序紧凑排列。
【插入数据】push
首先在堆的末尾插入数据,然后不断向上提升直到没有大小颠倒
【删除数据】pop
从堆中删除最小的数据
先将堆中最后一个节点的值复制到根节点上,并且删除最后一个节点。然后不断向下交换,直到没有大小颠倒;
在向下交换的过程中,如果有两个儿子,则与其中较小的交换(如果儿子比自己小)。
【堆的操作复杂度】
两种操作都与树的深度成正比。 因此,如果有n个元素,那么每个操作的复杂度为O(logn);
【堆的实现】
给每个元素按照从上到下从左到右的顺序编号,并用数组来储存,此时儿子的编号满足如下性质
1.左儿子的编号是自己编号 x 2 + 1;
2.右儿子的编号是自己编号 x 2 + 2;
#include <iostream>
using namespace std;
const int maxn=10000;
class priority_q{
public:
priority_q(){
sz = 0; //size 初始化为0;
}
void push(int x);
int pop();
int size(){
return this->sz;
}
private:
int heap[maxn],sz;
};
void priority_q::push(int x){
int i = sz++;
while(i > 0){
// 父亲节点的编号
int p = (i - 1)/2;
if(heap[p] <= x) break;
//把父亲的节点放下来
heap[i] = heap[p];
//当前节点更新
i = p;
}
heap[i] = x;
}
int priority_q::pop(){
int ret = heap[0]; //根,最小值
int x = heap[--sz]; //最后一个节点, 放到根的数值
int i = 0;
//从根向下交换
while(i * 2 + 1< sz){
int a= i * 2 + 1, b= i * 2 + 2; //两个儿子的位置
if(b < sz && heap[b]< heap[a]) a = b; //选出 最小的儿子
if(heap[a] >= x) break; //如果没有大小颠倒 退出
//把儿子的值提上来
heap[i] = heap[a];
i = a;
}
heap[i] = x; //最终在找到的位置 i 填入 x;
return ret;
}
int main(){
priority_q pq;
pq.push(5);
pq.push(10);
pq.push(7);
pq.push(2);
int size = pq.size();
for(int i = 0; i < size; i++){
cout<<"第"<<i+1<<"个数"<<pq.pop()<<endl;
}
return 0;
}
搞笑的是,在我敲完上面这段代码运行的时候,360说这个是木马!搞得我关掉360杀毒才成功运行