手寫堆的兩種方法
阿新 • • 發佈:2021-06-15
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 }