1. 程式人生 > 其它 >手寫堆的兩種方法

手寫堆的兩種方法

1.插入式建立堆(HeapInsert)

適用於逐個插入,或者事先不知道有多少個元素。通過不斷往堆裡面插入元素,不斷進行調整來構建堆。HeapInsert是一種類似上浮的操作。

詳細過程請看上一篇部落格。

2.通過原有陣列建堆(Heapify)

從最後一個非葉子節點往前列舉,一直到根結點進行堆化的調整。如果當前節點小於某個自己的孩子節點(大根堆中),那麼當前節點和這個孩子交換。Heapify是一種類似下沉的操作。

具體例題:洛谷 P2085

思路:先將x取1的函式值放到堆裡,每次取出堆頂元素,再獲得該堆頂元素對應的函式編號,將該函式的x變為2,再替換掉堆頂元素,調整堆。一直迴圈m次即可。

程式碼如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int N=10010;
 5 int n,m,A[N],B[N],C[N],f[N],heap_size;
 6 struct  Heap{
 7     int val;
 8     int num;
 9 }h[N];
10 
11 void Swap(int x,int y){
12     int t;
13     t=h[x].val;
14     h[x].val=h[y].val;
15     h[y].val=t;
16 t=h[x].num; 17 h[x].num=h[y].num; 18 h[y].num=t; 19 } 20 21 void heapify(int i){ 22 int l=2*i; 23 int r=2*i+1; 24 int minn; 25 minn=i; 26 if(l<=heap_size) 27 minn=(h[l].val<h[i].val?l:i); 28 if(r<=heap_size) 29 minn=(h[r].val<h[minn].val?r:minn);
30 if(minn!=i){ //如果當前節點比左右子樹節點小,則交換 31 Swap(i,minn); 32 heapify(minn); 33 } 34 } 35 //從最後一個非葉子節點開始往前遍歷每一個節點 36 void build_heap(){ 37 for(int i=heap_size/2;i>0;i--){ 38 heapify(i); 39 } 40 } 41 int main(){ 42 scanf("%d%d",&n,&m); 43 for(int i=1;i<=n;i++) 44 { 45 cin>>A[i]>>B[i]>>C[i]; 46 f[i]=1; 47 h[i].val=A[i]*f[i]*f[i]+B[i]*f[i]+C[i]; 48 h[i].num=i; 49 } 50 heap_size=n; 51 build_heap(); 52 for(int i=1;i<=m;i++){ 53 printf("%d ",h[1].val); 54 f[h[1].num]++; 55 h[1].val=A[h[1].num]*f[h[1].num]*f[h[1].num]+B[h[1].num]*f[h[1].num]+C[h[1].num]; 56 heapify(1); 57 } 58 return 0; 59 }