C++ P3378 【模板】堆
先看了一下《演算法》,大概懂了基本原理之後,先抄了一遍題解,然後做了一遍。做的時候發現了幾處錯誤,第五次的時候成功AC
程式碼:
#include<cstdio> #include<iostream> #include<cctype> using namespace std; int heap[50001]; int heap_size=0; inline int readint(){ char c=getchar(); while(!isdigit(c)){ c=getchar(); } int n=0; while(isdigit(c)){ n=n*10+c-'0'; c=getchar(); } return n; } void put(int a){ int now,next; heap[++heap_size]=a; now=heap_size; while(now>1){ next=now/2; if(heap[now]>=heap[next])return; swap(heap[now],heap[next]); now=next; } } void del(){ int now,next; heap[1]=heap[heap_size--];//heap[1]=0;swap(heap[1],heap[heap_size]); now=1; while(now*2<=heap_size){//注意:這裡應該是 now*2<=heap_size 而不是next<heap_size 或 next<=heap_size next=now*2; if(heap[next+1]<heap[next])next++;//if(heap[next]<heap[next+1])next++; if(heap[next]>=heap[now])return; swap(heap[next],heap[now]); now=next; } } int get(){ return heap[1]; } int main(){ int n; cin>>n; for(int i=0;i<n;i++){ int input; input=readint(); //cout<<"INPUT: "<<input; if(input==1){ int input2; input2=readint(); //cout<<"read 2"; put(input2); }else if(input==2){ cout<<get()<<endl; }else if(input==3){ del(); } } }
小根堆:
1.插入
假設你已經有一個堆了,就是上面那個
這個時候你如果想要給它加入一個節點怎麼辦,比如說0?
先插到堆底(嚴格意義上來說其實0是在5的左兒子的,圖沒畫好放不下去,不過也不影響)
然後你會發現它比它的父親小啊,那怎麼辦?不符合小根堆的性質了啊,那就交換一下他們的位置
交換之後還是發現不符合小根堆的性質,那麼再換
還是不行,再換
好了,這下就符合小根堆的性質了,是不是順眼很多了?(假的,圖越來越醜,原諒我不想再畫)
事實上堆的插入就是把新的元素放到堆底,然後檢查它是否符合堆的性質,如果符合就丟在那裡了,如果不符合,那就和它的父親交換一下,一直交換交換交換,直到符合堆的性質,那麼就插入完成了
2.刪除
把0插入完以後,忽然你看這個0不爽了,本來都是正整數,怎麼就混進來你這個0?
於是這時候你就想把它刪除掉
怎麼刪除?在刪除的過程中還是要維護小根堆的性質
如果你直接刪掉了,那就沒有堆頂了,這個堆就直接亂了,所以我們要保證刪除後這一整個堆還是個完好的小根堆
首先在它的兩個兒子裡面,找一個比較小的,和它交換一下,但是還是沒法刪除,因為下方還有節點,那就繼續交換
還是不行,再換
再換
好了,這個礙眼的東西終於的下面終於沒有節點了,這時候直接把它扔掉就好了
這樣我們就完成了刪除操作,但是在實際的程式碼操作中,並不是這樣進行刪除操作的,有一定的微調,程式碼中是直接把堆頂和堆底交換一下,然後把交換後的堆頂不斷與它的子節點交換,直到這個堆重新符合堆性質(但是上面的方式好理解啊)
(以上內容出自這裡)
題目地址:https://www.luogu.org/problemnew/show/P3378