【模板】堆
阿新 • • 發佈:2019-03-15
int algorithm mage 有一個 tor n) long long 小根堆 \n
?堆是一種特殊的完全二叉樹。以小根堆為例,這種完全二叉樹有一個特點,就是它的父節點都比子節點小。符合這樣特點的二叉樹,我們也稱為最小堆。
?反之,如果所有父節點都比子節點要大,這樣的完全二叉樹稱為大根堆,或最大堆。
?(若是最小堆,則最小的數在堆頂/樹根。)
按一般意義來講,一個堆的父節點的優先級都比子節點高。
堆有兩種基本的寫法
1.手寫堆
#include <algorithm> #include <iostream> #include <cstdio> #include <cmath> #define leftson (cur<<1) #define rightson (cur<<1|1) #define father (cur>>1) #define int long long #define MAXN 1000000+10 int n=0,m; int heap[MAXN]; namespace self { #define int long long void swap(int h[],int x,int y) { int t; t=h[x]; h[x]=h[y]; h[y]=t; return; } using namespace self; void siftdown(int h[],int i) { int t; bool flag=0; while (i*2<=n && flag==0) { if (h[i]>h[i*2]) t=i*2; else t=i; if (i*2+1<=n) { if(h[t]>h[i*2+1]) t=i*2+1; } if (t!=i) { swap(heap,t,i); i=t; } else flag=1; } return; } } using namespace self; void down(int cur) { int t; bool flag=0; while (leftson<=n&&(!flag)) { if (heap[cur]>heap[leftson]) { t=leftson; } else t=cur; if (rightson<=n) { if (heap[t]<heap[rightson]) { t=rightson; } } if (t!=cur) { swap(heap,t,cur); cur=t; } else flag=1; } } void up(int cur) { bool flag=0; if (cur==1) return; while (cur!=1&&(!flag)) { if (heap[cur]<heap[father]) { swap(heap,cur,father); } else flag=1; cur=father; } return; } signed main() { scanf("%lld",&m); int q; while (m--) { scanf("%lld",&q); if (q==1) { n++; scanf("%lld",&heap[n]); up(n); continue; } if (q==2) { printf("%lld\n",heap[1]); continue; } if (q==3) { heap[1]=heap[n]; n--; siftdown(heap,1); } } return 0; }
無良無分析式玄學代碼
2.STL 堆:優先隊列
?隊列是一種先進先出(FIFO)式的數據結構。優先隊列與其不同的地方是,優先隊列存儲的時候,會將(定義的)優先級較大的元素放在較小的元素之前。也就是說優先級最大的元素放在隊頭。 那麽這裏就和堆有了共同點:優先級大的放在隊前/堆高層。
大根堆的定義:
queue< int >q;
小根堆的定義:
priority_queue< int,vector< int >,greater< int > >q;
一個優先隊列的操作:
小根堆基本操作代碼
#include <algorithm> #include <iostream> #include <cstdio> #include <cmath> #include <queue> using namespace std; priority_queue<int,vector<int>,greater<int> >q; int main() { int n; scanf("%d",&n); int x; while(n--) { scanf("%d",&x); if (x==1)//命令1 在堆中加入一個數 { scanf("%d",&x); q.push(x); continue; } if (x==2)//命令2 輸出當前序列中最小數 { printf("%d\n",q.top()); continue; } if (x==3)//命令3 刪除當前序列中最小數 q.pop(); } return 0; }
【模板】堆