思路:用两个堆, 大顶堆和小顶堆。每次输入一个数,如果这个数比当前的中位数大,就存入小顶堆中, 否则就存入大顶堆。然后调整, 小顶堆元素的个数要等于大顶堆的元素个数,或者比其多1。如果小顶堆的元素太多,就塞到大顶堆里,反之亦然。
实际上还可以加上删除中位数操作:只要保证大顶堆的元素=小顶堆的元素或者比小顶堆元素多一即可。这样的数据结构实现了:增加一个元素在log(n)时间内完成,其中n是该数据结构中当前元素的个数。注意:数据结构中允许有重复的元素。(2) 返回当前元素集合的中位数,在常数时间内完成。如果当前元素的个数为偶数,那么返回下中位数(即两个中位数中较小的一个)。(3) 删除中位数,在log(n)时间内完成。
3784代码:
#include <cstdio> #include <queue> #include <algorithm> #include <cstring> #include <cmath> using namespace std; #define INF 0x3fffffff #define clr(s,t) memset(s,t,sizeof(s)); priority_queue<int> h1; priority_queue<int,vector<int>,greater<int>> h2; int T,c,n,len1,len2; void insert(int x){ int j; if(!len1 && !len2){ h1.push(x); len1 ++; return; } if(x <= h1.top()){ if(len1 == len2){ h1.push(x); len1++; }else{ h1.push(x); j = h1.top(); h1.pop(); h2.push(j); len2++; } }else{ if(len1 == len2){ h2.push(x); j = h2.top(); h2.pop(); h1.push(j); len1++; }else{ h2.push(x); len2++; } } } int query(){ return h1.top(); } int main(){ scanf("%d",&T); while(T--){ int i,x; while(!h1.empty()) h1.pop(); while (!h2.empty()) h2.pop(); len1 = len2 = 0; scanf("%d %d",&c,&n); printf("%d %d\n",c,(n+1)>>1); c = 19; for(i = 1;i<=n;i++){ scanf("%d",&x); insert(x); if(i&1) printf("%d ",query()); if(i == c){ printf("\n"); c += 20; } } printf("\n"); } return 0; }
3784版本2:手动实现堆,不用stl。并且用结构体将两个堆“封装”。
#include <stdio.h> #include <string.h> #include <stdlib.h> #define INF 0x3fffffff #define N 10005 struct NewDataStruct{ int *h1,*h2; int len1,len2; }; struct NewDataStruct* CreateNewDataStruct(){ struct NewDataStruct *ds = (struct NewDataStruct*)malloc(sizeof(struct NewDataStruct)); ds->h1 = (int*)malloc(N*sizeof(int)); ds->h2 = (int*)malloc(N*sizeof(int)); ds->len1 = ds->len2 = 0; ds->h1[0] = INF; ds->h2[0] = -INF; return ds; } void siftDownMin(int *heap, int size) { int i = 1; int x = heap[i]; i <<= 1; while(i<=size){ if(i+1<=size && heap[i+1]<heap[i]) i++; if(x < heap[i]) break; heap[i/2] = heap[i]; i <<= 1; } heap[i/2] = x; } void siftDownMax(int *heap, int size) { int i = 1; int x = heap[i]; i <<= 1; while(i<=size){ if(i+1<=size && heap[i+1]>heap[i]) i++; if(x > heap[i]) break; heap[i/2] = heap[i]; i <<= 1; } heap[i/2] = x; } void siftUpMin(int *heap, int size){ int i,x = heap[size]; i = size; while(i>=1){ if(heap[i/2] <= x) break; heap[i] = heap[i/2]; i >>= 1; } heap[i] = x; } void siftUpMax(int *heap, int size){ int i,x = heap[size]; i = size; while(i>=1){ if(heap[i/2] >= x) break; heap[i] = heap[i/2]; i >>= 1; } heap[i] = x; } void addOneNumber(struct NewDataStruct* mf,int x){ if(!mf->len1 && !mf->len2){ mf->h1[++mf->len1] = x; return; } if(mf->len1 == mf->len2){ if(x > mf->h2[1]){ mf->h1[++mf->len1] = mf->h2[1]; siftUpMax(mf->h1, mf->len1); mf->h2[1] = x; siftDownMin(mf->h2, mf->len2); }else{ mf->h1[++mf->len1] = x; siftUpMax(mf->h1, mf->len1); } }else{ if(x>=mf->h1[1]){ mf->h2[++mf->len2] = x; siftUpMin(mf->h2, mf->len2); }else{ mf->h2[++mf->len2] = mf->h1[1]; siftUpMin(mf->h2, mf->len2); mf->h1[1] = x; siftDownMax(mf->h1, mf->len1); } } } int findMedianNumber(struct NewDataStruct* mf){ return mf->h1[1]; } void MedianFinderFree(struct NewDataStruct* mf){ free(mf); } int main(){ int T,c,n; scanf("%d",&T); while(T--){ int i,x; struct NewDataStruct* mf = CreateNewDataStruct(); scanf("%d %d",&c,&n); printf("%d %d\n",c,(n+1)>>1); c = 19; for(i = 1;i<=n;i++){ scanf("%d",&x); addOneNumber(mf, x); if(i&1) printf("%d ",findMedianNumber(mf)); if(i == c){ printf("\n"); c += 20; } } printf("\n"); MedianFinderFree(mf); } }
如果加上删除:
#include <cstdio> #include <queue> #include <algorithm> #include <cstring> #include <cmath> using namespace std; #define INF 0x3fffffff #define clr(s,t) memset(s,t,sizeof(s)); priority_queue<int> h1; priority_queue<int,vector<int>,greater<int>> h2; int T,c,n,len1,len2; void insert(int x){ int j; if(!len1 && !len2){ h1.push(x); len1 ++; return; } if(x <= h1.top()){ if(len1 == len2){ h1.push(x); len1++; }else{ h1.push(x); j = h1.top(); h1.pop(); h2.push(j); len2++; } }else{ if(len1 == len2){ h2.push(x); j = h2.top(); h2.pop(); h1.push(j); len1++; }else{ h2.push(x); len2++; } } } int query(){ return h1.top(); } void del(){ int j; if(len1 == len2){ h1.pop(); j = h2.top(); h2.pop(); h1.push(j); len2--; }else{ len1--; h1.pop(); } } int main(){ scanf("%d",&T); while(T--){ int i,x; char ch; while(!h1.empty()) h1.pop(); while (!h2.empty()) h2.pop(); len1 = len2 = 0; scanf("%d",&n); for(i = 1;i<=n;i++){ getchar(); ch = getchar(); if(ch == 'I'){ scanf("%d",&x); insert(x); }else if(ch == 'Q') printf("%d\n",query()); else del(); } } return 0; }