堆的两种操作所花的时间都和树的深度成正比.因此,如果一共有n个元素,那么每个操作可以在O(logn)时间内完成.
堆的实现
1.左儿子的编号是自己的编号*2+1
2.右儿子的编号是自己的编号*2+1
push和pop的实现:
1 int heap[MAX],sz=0; 2 3 void push(int x) 4 { 5 //自己节点的编号 6 int i=sz++; 7 8 while(i>0){ 9 //父亲节点的编号 10 int p=(i-1)/2; 11 12 //如果已经没有大小颠倒则退出 13 if(heap[p]<=x) break; 14 15 //把父亲节点的数值放下来,而把自己提上去 16 heap[i]=heap[p]; 17 i=p; 18 } 19 } 20 21 int pop() 22 { 23 //最小值 24 int ret=heap[0]; 25 26 //要提到根的数值 27 int x=heap[--sz]; 28 29 //从根开始向下交换 30 int i=0; 31 while(i*2+1<sz){ 32 //比较儿子的值 33 int a=i*2+1,n=i*2+2; 34 if(b<sz && heap[b]<heap[a]) a=b; 35 36 //如果已经没有大小颠倒则退出 37 if(heap[a]>=x) 38 break; 39 40 //把儿子的数组提上来 41 heap[i]=heap[a]; 42 i=a; 43 } 44 heap[i]=x; 45 return ret; 46 }
编程语言的标准库:
实际上,大部分情况并不需要自己实现堆.在许多编程语言的标准中,都包含了优先队列的高效实现.例如在c++中,STL里的priority_queue就是其中之一.不过需要注意的是,priority_queue与上面讲的优先队列有所不同,取出数值得到的是最大值.
1 #include <queue> 2 #include <cstdio> 3 using namespace std; 4 5 int main() 6 { 7 //声明 8 priority_queue<int> p; 9 10 //插入元素 11 p.push(3); 12 p.push(5); 13 p.push(1); 14 15 //不断循环直到空为止 16 while(!p.empty()){ 17 //获取并删除最大值 18 printf("%d ",p.top()); 19 p.pop(); 20 } 21 return 0; 22 }