您的位置:首页 > 其它

【优先队列:支持动态插入,寻找中位数】:poj3784,Running Median

2016-01-07 15:26 357 查看
维护一个最大堆和一个最小堆, 首先先将前两个元素中较大的加入最小

堆,较小的加入最大堆。然后每次添加新元素的时候,先将其与最大堆和最小堆的堆顶进行对比,

如果其大于最小堆堆顶则插入最小堆,如果其小于最大堆堆顶则插入最大堆,否则选择元素数量

较小的一堆。 在插入与向上调整结束后, 如果两堆的元素数量差大于
1(即为
2),则从元素数量

较多的一堆中取出堆顶插入另一堆,两堆相应进行向下向上调整,这样可以保证两堆元素数量始

终是平衡的。 在这种情况下,选取中位数只需要选取元素数量多
1 的一堆的堆顶,或者两堆元素

数量相同的时候选择两堆堆顶的平均数即可。

# include<iostream>
# include<queue>
using namespace std;

int main()
{
    int p,n,m,i,j,k;

    cin>>p;
    for(i=1;i<=p;i++)
    {
        cin>>n>>m;
        cout<<n<<" "<<m/2+1<<endl;
        if(m==1)
        {
            cin>>k;
            cout<<k<<endl;
        }
        else
        {
            priority_queue<int, vector<int>, less<int> > pqB;
            priority_queue<int, vector<int>, greater<int> > pqS;

            cin>>n>>k;
            cout<<n<<" ";
            if(n>k)
            {
                pqB.push(k);
                pqS.push(n);
            }
            else
            {
                pqB.push(n);
                pqS.push(k);
            }
            for(j=3;j<=m;j++)
            {
                cin>>k;
                //insert
                if(k>pqS.top())
                {
                    pqS.push(k);
                }
                else if(k<pqB.top())
                {
                    pqB.push(k);
                }
                else
                {
                    if(pqB.size()>pqS.size())
                    {
                        pqS.push(k);
                    }
                    else
                    {
                        pqB.push(k);
                    }
                }
                //adjust
                if(pqB.size()>pqS.size()+1)
                {
                    while(pqB.size()>pqS.size()+1)
                    {
                        k=pqB.top();
                        pqB.pop();
                        pqS.push(k);
                    }
                }
                if(pqS.size()>pqB.size()+1)
                {
                    while(pqS.size()>pqB.size()+1)
                    {
                        k=pqS.top();
                        pqS.pop();
                        pqB.push(k);
                    }
                }

                if(j%2==1)
                {
                    if(pqB.size()>pqS.size())
                    {
                        cout<<pqB.top();
                    }
                    if(pqS.size()>pqB.size())
                    {
                        cout<<pqS.top();
                    }

                    if(j%20==19)
                    {
                        cout<<endl;
                    }
                    else
                    {
                        cout<<" ";
                    }
                }

            }
            cout<<endl;
        }
    }

    return 0;
}



n>>k 的情况下,在一遍读取后取出n
个数据中最大的k
个数据

提供以下两种做法:

1, 建立一个大小为k
的最小堆, 先用数据的前
k 项创建一个堆(不用依次添加入堆中),之

后每次将读入的数据与堆顶的数据进行对比,如果比堆顶数据小则舍去,如果比堆顶数据大则将

堆顶的数据替换为读入的数据然后对其进行向下调整。考虑到
n>>k,则其时间代价
nlogk 可近似

视为
O(n)。

2, 取前k
个数据排序, 然后再取
k 个数据排序, 对两组数据进行归并合并,然后舍去后
k

个数据并继续读取硬盘数据直到数据读完。 在
n>>k 的情况下,时间代价同样近似为
O(n)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: