双堆求中位数

堆的动态创建与删除可参考 http://www.java3z.com/cwbwebhome/article/article1/1362.html?id=4745,此处不再赘述。

双堆求中位数

算法描述:

1、创建两个堆(一个小根堆、一个大根堆),堆大小至少为给定数据个数的一半,向上取整;

2、假定变量mid用来保存中位数,取定第一个元素,赋值给mid,即作为初始的中位数;

3、依次遍历后面的每一个数据,如果比mid小,则插入大根堆;否则插入小根堆;

4、如果大根堆和小根堆上的数据个数相差为2,则将mid插入到元素个数较少的堆中,然后从元素个数较多的堆中删除根节点,并将跟节点赋值给mid;

5、重复步骤3和4,直到所有的数据遍历结束;

此时,mid保存了一个数,再加上两个堆中保存的数,就构成了给定数据的集合。

如果两个堆中元素个数相等,则mid即为最终的中位数;否则,元素较多的堆的根节点元素与mid的和求平均值,即为最终的中位数。

算法实现

算法实现采用了整数,所以,最终的结果取了整数,可以将返回值转换为浮点型,更精确。

uint32_t getmiddle(uint32_t *array, uint32_t size)
{
  int i = 0, minelem = 0, maxelem = 0;
  uint32_t mid = array[0];
  uint32_t heapsize = (size+1)/2;
  heap_t *minheap = heap_malloc(heapsize);
  heap_t *maxheap = heap_malloc(heapsize);
  for(i = 1; i < size; i++)
  {
    if(array[i] < mid)
    {
      maxheap_insert(maxheap, array[i]);
      maxelem++;
    }
    else
    {
      minheap_insert(minheap, array[i]);
      minelem++;
    }
    if(minelem - maxelem > 1)
    {
      maxheap_insert(maxheap, mid);
      mid = minheap->element[0];
      minheap_delete(minheap);
      maxelem++;
      minelem--;
    }
    if(maxelem - minelem > 1)
    {
      minheap_insert(minheap, mid);
      mid = maxheap->element[0];
      maxheap_delete(maxheap);
      minelem++;
      maxelem--;
    }
  }

  printf("\nmaxelem = %d, minelem = %d, pre_mid = %d\n", maxelem, minelem,mid);

  if(minelem > maxelem)
  {
    printf("\nmid[ %d ] = ( mid [ %d ]+minheap->element[0][ %d ] )/2 = %d\n",mid, mid,
      minheap->element[0],(mid+minheap->element[0])/2);
    mid = (mid+minheap->element[0])/2;
  }
  if(maxelem < maxelem)
  {
      printf("\nmid[ %d ] = ( mid [ %d ]+maxheap->element[0][ %d ] )/2 = %d\n",mid, mid,
      minheap->element[0],(mid+maxheap->element[0])/2);
    mid = (mid+maxheap->element[0])/2;
  }

  heap_free(minheap);
  heap_free(maxheap);
  return mid;
}

测试程序

int main(int argc, char *argv[])
{
  int num = 10;
  uint32_t array[num] = {2,20,13,18,15,8,3,5,4,25};
  getmiddle(array, num);
  printf("\n");
  return 0;
}

测试结果

时间: 2024-10-08 03:07:51

双堆求中位数的相关文章

求中位数总结

今天在某个群中看到有人问在流式的数据中如何动态的维护中位数的方法,因为之前看到同学的一个问题,当时他没答出来.但是后来了解到类似top(k),last(k)需要用到最大堆,最小堆一样,中位数需要利用双堆维护一下. 先复习一下,如果是静态的数据求取中位数的方法有哪些呢? (1)排序 (2)fink-k 这两种方法不太适合于流式的数据动态变更中位数,所以就引出了双堆求取中位数的策略: 算法如下: 1.初始化的时候设置两个变量分别记录两个堆[左堆和右堆]的元素的个数. 2.取第一个元素[d[0]]作为

POJ 3784 Running Median 动态求中位数 堆

题意. 1000个case 每个case 输入若干个数,对第k个输入,如果k为奇数,则输出前k个数的中位数 那么这就是动态求中位数了 实现的思路也比较简洁 用两个堆, 大顶堆和小顶堆 每次输入一个数,如果这个数比当前的中位数大,就存入小顶堆中,  否则就存入大顶堆. 然后调整, 小顶堆元素的个数要等于大顶堆的元素个数,或者比其多1. 如果小顶堆的元素太多,就塞到大顶堆里,反之亦然 这样一来就会发现.小顶堆的元素比所有大顶堆的元素都大, 而且小顶堆的堆顶就是中位数. 那么怎么样才能想到这样一个思路

在线求中位数

在线求第k个数做得多了,在线求中位数也是用堆,一个最大堆,一个最小堆. 思想大概是这样子的: 一个最大堆,一个最小堆,最大堆对应于前n/(n+1)个数,最小堆对应于后n/n+1个数:假设最大堆堆项元素为n1, 最小堆堆顶为n2, 则n1 <= n2; 确保两个堆的大小最多只差1. 设最大堆大小为s1, 最小堆大小为s2,则abs(s1-s2) <= 1: 对于新来的数m,分情况调整: 如果s1== s2, 那么:如果m<= n2, m插入到最大堆,s1= s1+1; 否则插入到最小堆,s

URAL 1306 - Sequence Median 小内存求中位数

[题意]给出n(1~250000)个数(int以内),求中位数 [题解]一开始直接sort,发现MLE,才发现内存限制1024k,那么就不能开int[250000]的数组了(4*250000=1,000,000大约就是1M内存). 后来发现可以使用长度为n/2+1的优先队列,即包含前一半的数以及中位数,其他数在读入的时候就剔除,这样可以省一半的空间. 1 #include<bits/stdc++.h> 2 #define eps 1e-9 3 #define FOR(i,j,k) for(in

POJ 2388 Who&#39;s in the Middle(水~奇数个数排序求中位数)

题目链接:http://poj.org/problem?id=2388 题目大意: 奇数个数排序求中位数 解题思路:看代码吧! AC Code: 1 #include<stdio.h> 2 #include<algorithm> 3 using namespace std; 4 int main() 5 { 6 int n; 7 while(scanf("%d",&n)!=EOF) 8 { 9 int na[n+1]; 10 for(int i=0; i

POJ 3177 边双连通求连通量度的问题

这道题的总体思路就是找到连通量让它能够看作一个集合,然后找这个集合的度,度数为1的连通量为k,那么需要添加(k+1)/2条边才可以保证边双连通 这里因为一个连通量中low[]大小是相同的,所以我们用ans[low[i]]++来计度数 这道题我最开始按学长的模板来写....MLE到哭了,也不知道这道题为什么这么逗,把5000的数组改成1000也能过,当然后来换了别的思路 为了防止重边的进入,开始设置了一个hash[][]二维数组来判断边是否已经存在,不额外添入 之后,我不采用二维数组,而是在get

求中位数

求中位数 题目描述 输入n和n个数,求大于中位数的数据个数.(n小于50) 中位数是把一列数从小到大排列后,中间的那个数!如果那一列数是偶数,就取中间两个数的平均数! 例如: 第1组数:1.2.3.6.7的中位数是3. 第2组数:1.2.3.5的中位数是2.5. 输入描述 输入正整数n和n个实数 输出描述 1.输出中位数保留小数1位.中位数输出占一行. 2.输出大于中位数的数据个数占一行. 样例输入 4 1 2 3 5 样例输出 2.5 2

hdoj 4738 Caocao&#39;s Bridges【双连通分量求桥】

Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3000    Accepted Submission(s): 953 Problem Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. Bu

Uva 10765 点双连通求删任意点后剩下图中的连通分量数

题目挂在wustoj上,不知道什么原因不能粘贴链接.. 第一题题号为1314..这题是智力题...换成7的阶乘就可以了.. 代码如下. #include<cstdio> int main() { printf("...............................................................................................\n"); printf("..#................