基本思想: 两种操作都跟树的深度成正比,所以复杂度 O(log(n)) ;
push():在向堆中插入数值时,首先在堆的末尾插入该数值,然后不断向上提直到没有大小颠倒为止。
pop(): 从堆中取出一个数值时,首先把堆的最后一个节点的数值复制到根节点上,并且删除最后一个节点,然后不断向下交换直到没有大小颠倒为止,在向下交换的时候,如果有两个儿子,那就选择数值较小的(如果可以交换的话)进行交换。
数组实现:
1 #include <cstdio> 2 const int maxn = 10000; 3 int heap[maxn], sz=0; 4 5 void push(int x) { 6 int i = sz++; 7 while(i > 0) { 8 int p = (i-1) / 2; //p是父亲节点的编号 9 if(heap[p] <= x) break; //如果没有大小颠倒则退出 10 heap[i] = heap[p]; //把父亲节点 放下来 ,而把自己提上去 11 i = p; 12 } 13 heap[i] = x; //把 x放入 正确的位置 14 } 15 16 int pop() { 17 int ret = heap[0]; //最小值 18 int x = heap[--sz]; //要提到根的数值 19 20 int i = 0; //从根开始向下交换 21 while(i * 2 + 1 < sz) { //可能 只有 一个 儿子 22 int a = i * 2 + 1, b = i * 2 + 2; //两个儿子的 编号 23 if(b < sz && heap[b] < heap[a]) a=b; //如果 右儿子存在 并且 值比 左儿子小 则交换 24 if(heap[a] >= x) break; //如果不能交换 就退出 25 heap[i] = heap[a]; //把儿子的 数值提上来 26 i=a; 27 } 28 heap[i] = x; 29 return ret; 30 } 31 32 int main() 33 { 34 push(1); 35 push(2); 36 push(10); 37 push(7); 38 push(4); 39 40 int x1 = pop(); 41 int x2 = pop(); 42 43 printf("%d %d ",x1,x2); 44 for(int i = 0; i< sz; i++) 45 printf("%d ", heap[i]); 46 return 0; 47 }
STL:
priority_queue 默认取出的是最大值。
priority_queue<int, vector<int>, greater<int> >que; 从小到大
priority_queue<int, vector<int>, less<int> >que; 从大到小
1 #include <iostream> 2 #include <queue> 3 using namespace std; 4 5 int main() { 6 priority_queue<int> que; 7 8 que.push(5); 9 que.push(2); 10 que.push(1); 11 12 while(que.size()) { 13 cout << que.top() << endl; 14 que.pop(); 15 } 16 return 0; 17 }