poj 3784 带插入的动态查询中位数

题意:输入若干个数,对第k个输入,如果k为奇数,则输出前k个数的中位数。

思路:用两个堆, 大顶堆和小顶堆。每次输入一个数,如果这个数比当前的中位数大,就存入小顶堆中, 否则就存入大顶堆。然后调整, 小顶堆元素的个数要等于大顶堆的元素个数,或者比其多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;
}


你可能感兴趣的:(poj 3784 带插入的动态查询中位数)