poj 3784 用堆动态求解中位数

堆真是一种简单而又神奇的数据结构,以前用它求过前kth的数,现在又可以用两个堆来动态求解中位数。

算法:

  构建一个大顶堆和一个小顶堆,分别记为g和l。

  假设当前中位数为mid,新读入一个数为tmp,则:

  1.如果tmp < mid,则将tmp插入大顶堆,跳到步骤3。

  2.如果tmp >= mid,则将tmp插入小顶堆,跳到步骤4。

  3.如果大顶堆的元素个数比小顶堆多2(两个堆个数不平衡),则将mid插入小顶堆,弹出大顶堆堆顶元素为新的mid。

  4.与步骤3相反,如果小顶堆的元素个数比大顶堆多2,则将mid插入大顶堆,弹出小顶堆堆顶元素为新的mid。

  5.如果两个堆元素个数相同,则mid即为当前序列的中位数;否则,中位数为mid和元素个数较多的堆的堆顶元素的平均值,至此算法描述结束。

也有人把这个叫做最大最小堆或者是对顶堆的。

示例代码poj3784:

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <queue>
 5 using namespace std;
 6 
 7 priority_queue<int, vector<int>, less<int> > g;
 8 priority_queue<int, vector<int>, greater<int> > l;
 9 const int N = 10000;
10 int ans[N];
11 int p;
12 
13 int main ()
14 {
15     int t;
16     scanf("%d", &t);
17     while ( t-- )
18     {
19         int _case, n, mid;
20         scanf("%d%d%d", &_case, &n, &mid);
21         printf("%d %d\n", _case, ( n + 1 ) / 2);
22         p = 0;
23         ans[p++] = mid;
24         while ( !l.empty() ) l.pop();
25         while ( !g.empty() ) g.pop();
26         for ( int i = 2; i <= n; i++ )
27         {
28             int tmp;
29             scanf("%d", &tmp);
30             if ( tmp < mid )
31             {
32                 g.push(tmp);
33                 if ( g.size() - l.size() == 2 )
34                 {
35                     l.push(mid);
36                     mid = g.top();
37                     g.pop();
38                 }
39             }
40             else
41             {
42                 l.push(tmp);
43                 if ( l.size() - g.size() == 2 )
44                 {
45                     g.push(mid);
46                     mid = l.top();
47                     l.pop();
48                 }
49             }
50             if ( i & 1 )
51             {
52                 ans[p++] = mid;
53             }
54         }
55         for ( int i = 0; i < p; i++ )
56         {
57             printf("%d", ans[i]);
58             if ( i % 10 == 9 || i == p - 1 )
59             {
60                 putchar('\n');
61             }
62             else
63             {
64                 putchar(' ');
65             }
66         }
67     }
68     return 0;
69 }

 

  

转载于:https://www.cnblogs.com/huoxiayu/p/4645268.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值