算法:动态中位数问题

8人阅读 评论(0) 收藏 举报
分类:

题目描述

输入一组整数a1, a2, …, an ,每输入一个整数,输出到此时为止的中位数。

中位数定义:如果数串的大小是偶数 2j,中位数是从小到大排列的第 j 个数;如果数串的大小是奇数 2j+1,中位数是从小到大排列的第 j+1 个数。

输入

一组整数,数字和数字之间以空格隔开。

输出

一组整数,数字和数字之间以空格隔开。最后一个数后面也有空格。

第 i 个输出的整数,是前 i 个输入的中位数。

样例输入

-18 -2 14 -20 -6 7 2 14 11 6

样例输出

-18 -18 -2 -18 -6 -6 -2 -2 2 2

提示

时间复杂度请不要超过O(nlogn)。

算法分析

  本算法可以利用堆的结构来动态的求解一个数串的中位数。因为该题目要求动态的输入当前串的中位数。通过使用堆结构,通过维护一个大根堆和一个小根堆和一个中位数middle。构建堆只需要O(n)时间复杂度,而提取中位数则只需要线性时间复杂度O(1)。
  该算法将是高效的,但是在具体实现的过程中,特别是动态加入数串的过程中要平衡两个堆之间元素个数已确保middle是已经输入数串的中位数。具体而言:
 (1)、当最大根堆元素个数大于最小根堆元素个数时,弹出最大根堆堆顶元素给middle,原middle元素入最小根堆。
 (2)、当最小根堆元素个数-最小根堆元素个数>=2时,弹出最小根堆堆顶元素给middle,原middle元素入最大根堆。

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>

using namespace std;

void fix_min_heap(long *, long fix_num, long num); //修复小根堆的函数
void fix_max_heap(long *, long fix_num, long num); //修复大根堆的函数
void fix_min_heap_up(long *,  long up);//从底部向上修复最小根堆
void fix_max_heap_up(long *, long up);//从底部向上修复最大根堆

int main(void){
        long a = 0;
        long MAX_NUM_MIN = 4;
        long MAX_NUM_MAX = 4;
        long num = 0;
        long middle = 0;
        long left_size = 0;
        long right_size = 0;
        long * new_ptr = NULL;
        long middle1= 0, middle2 = 0;
        long *max_vec = (long*)malloc(sizeof(long) *(MAX_NUM_MAX + 1));
        long *min_vec = (long*)malloc(sizeof(long) *(MAX_NUM_MIN + 1));
        max_vec[0] = 0;//将第一个元素设为0
        min_vec[0] = 0;//将第一个元素设为0
        while(scanf("%ld" ,&a) != EOF){
                num ++;
                if(num <= 3){
                        switch (num){
                                case 1:
                                        middle = a;
                                        break;
                                case 2:
                                        middle2 = middle < a? a : middle;
                                        middle = middle < a? middle : a;
                                        break;
                                case 3:
                                        middle1 = a < middle? a : middle;
                                        middle = a < middle? middle:(a > middle2? middle2: a);
                                        middle2 = middle2 > a? middle2 : a;
                                        max_vec[1] = middle1;
                                        left_size++;
                                        min_vec[1] = middle2;
                                        right_size++;
                                        break;
                                default:
                                        break;
                        }
                }else{
                        if(a >= middle){
                                right_size++;
                                if(right_size >= MAX_NUM_MIN){
                                        MAX_NUM_MIN *= 2;
                                        new_ptr = (long*)malloc(sizeof(long) *(MAX_NUM_MIN+1));
                                        if(!new_ptr){
                                                return 0;
                                        }
                                        new_ptr[0] = 0;
                                        for(long i =1; i <= right_size ; ++i){
                                                new_ptr[i] = min_vec[i];
                                        }
                                        free(min_vec);
                                        min_vec = new_ptr;
                                }
                                min_vec[right_size] = a;
                                fix_min_heap_up(min_vec,  right_size);
                                if((right_size - left_size) >= 2){
                                        left_size++;
                                        if(left_size >= MAX_NUM_MAX){
                                                MAX_NUM_MAX *= 2;
                                                new_ptr = (long *)malloc(sizeof(long) * (MAX_NUM_MAX + 1));
                                                if(!new_ptr){
                                                        return 0;
                                                }
                                                new_ptr[0] = 0;
                                                for(long i =1; i <= left_size ; ++i){
                                                        new_ptr[i] = max_vec[i];
                                                }
                                                free(max_vec);
                                                max_vec = new_ptr;
                                        }
                                        max_vec[left_size] = middle;
                                        fix_max_heap_up(max_vec,  left_size);//进行最大根堆的修复
                                        middle = min_vec[1];//将最小根堆的堆顶作为middle
                                        min_vec[1] = min_vec[right_size];
                                        min_vec[right_size] = 0;
                                        right_size--;
                                        fix_min_heap(min_vec, 1, right_size);
                                }
                        }else{
                                left_size++;
                                if(left_size >= MAX_NUM_MAX){
                                        MAX_NUM_MAX *= 2;
                                        new_ptr = (long *)malloc(sizeof(long) * (MAX_NUM_MAX + 1));
                                        if(!new_ptr){
                                                return 0;
                                        }
                                        new_ptr[0] = 0;
                                        for(long i =1; i <= left_size ; ++i){
                                                new_ptr[i] = max_vec[i];
                                        }
                                        free(max_vec);
                                        max_vec = new_ptr;
                                }
                                max_vec[left_size] = a;
                                fix_max_heap_up(max_vec , left_size);
                                if((left_size - right_size) >= 1){
                                        right_size++;
                                        if(right_size >= MAX_NUM_MIN){
                                                MAX_NUM_MIN *= 2;
                                                new_ptr = (long*)malloc(sizeof(long) *(MAX_NUM_MIN+1));
                                                if(!new_ptr){
                                                        return 0;
                                                }
                                                new_ptr[0] = 0;
                                                for(long i =1; i <= right_size ; ++i){
                                                        new_ptr[i] = min_vec[i];
                                                }
                                                free(min_vec);
                                                min_vec = new_ptr;
                                        }
                                        min_vec[right_size] = middle;
                                        fix_min_heap_up(min_vec,  right_size);
                                        middle = max_vec[1];
                                        //进行最大根修复
                                        max_vec[1] = max_vec[left_size];
                                        max_vec[left_size] = 0;
                                        left_size--;
                                        fix_max_heap(max_vec, 1, left_size);
                                }
                        }
                }
                printf("%ld ", middle);
                a = 0;
        }
        free(min_vec);
        min_vec = NULL;
        free(max_vec);
        max_vec = NULL;
        return 0;
}


//构造小根堆
void fix_min_heap(long *p, long fix_num, long num){
        while(fix_num * 2 <= num ){
                long left = p[fix_num * 2];
                long temp = p[fix_num];
                long next = fix_num;
                if(fix_num * 2 <= num && left < temp){
                        next = fix_num * 2;
                }
                if(fix_num * 2+1 <= num && p[fix_num * 2 + 1] < temp&& p[fix_num * 2 + 1] < left){
                        next = fix_num * 2+1;
                }
                if(next != fix_num){
                        p[fix_num] = p [next];
                        p[next] = temp;//进行元素交换,将较小的元素浮出水面
                        fix_num = next;
                }else{
                        break;
                }
        }
}
//构造大根堆
void fix_max_heap(long * p, long fix_num, long num){
        while(fix_num * 2 <= num ){
                long left = p[fix_num * 2];
                long temp = p[fix_num];
                long next = fix_num;
                if(fix_num * 2 <= num && left > temp){
                        next = fix_num * 2;
                }
                if(fix_num * 2+1 <= num && p[fix_num * 2 + 1] > temp&& p[fix_num * 2 + 1] > left){
                        next = fix_num * 2+1;
                }
                if(next != fix_num){
                        p[fix_num] = p [next];
                        p[next] = temp;//进行元素交换,将较大的元素浮出水面
                        fix_num = next;
                }else{
                        break;
                }
        }
}

void fix_min_heap_up(long *p,  long up)//从底部向上修复最小根堆
{
        while(up != 1){
                long tem_up = up / 2;
                long temp = p[tem_up];
                long next = up;
                if (tem_up >= 1){
                        if (p[up] < temp){
                                next = tem_up;
                                p[next] =  p[up];
                                p[up] = temp;
                        }
                        if( next == up)
                                break;
                }
                up = next;
        }
}
void fix_max_heap_up(long *p,  long up)//从底部向上修复最大根堆
{
        while(up != 1){
                long tem_up = up / 2;
                long temp = p[tem_up];
                long next = up;
                if (tem_up >= 1){
                        if (p[up] > temp){
                                next = tem_up;
                                p[next] =  p[up];
                                p[up] = temp;
                        }
                        if( next == up)
                                break;
                }
                up = next;
        }
}
查看评论

数据结构和算法

本次课主要是介绍在游戏开发中经常使用的数据结构,例如数组,链表,栈,队列,二叉树,递归等重要知识点讲解以及将它们里灵活的运用到算法里面。
  • 2015年01月29日 08:45

POJ 3784 Running Median 动态求中位数 堆

题意。 1000个case 每个case   输入若干个数,对第k个输入,如果k为奇数,则输出前k个数的中位数 那么这就是动态求中位数了 实现的思路也比较简洁 用两个堆, ...
  • sdj222555
  • sdj222555
  • 2015-01-23 17:36:21
  • 2691

初识分治法,动态规划——中位数,Gray码与零钱问题

      通过学习“算法设计与分析”课程,我想对于那些经典的算法,除了在理论上“认识”他们外,最主要是在思想上学会他们,接受他们,这样不知不觉地培养了我们一种严密的思维能力,并且运用所学知识结合具体...
  • lin_bei
  • lin_bei
  • 2007-04-15 17:31:00
  • 9023

中位数问题(/C++)

 中位数 【题目描述】 有一个长度为N的数例(A1,A2,…,AN),这N个数字恰好是1. .N的一个排列。你需要统计有多少个子序例(Ai,Ai+1,…,Aj)满足:i= 【输入文件】 ...
  • caf2000
  • caf2000
  • 2015-08-03 12:55:39
  • 284

动态维护中位数

问题陈述:有个需要动态更新(插入或删除)的数列L,现在需要随时获取到该数列的中位数,请设计相应的数据结构和算法。   算法:令L的中位数为m,用一个大顶堆存储数列L中不大于m的元素(即L按...
  • guogaoan
  • guogaoan
  • 2014-08-14 11:36:12
  • 1128

堆排序:动态数组求中位数

题目描述输入一组整数a1, a2, …, an ,每输入一个整数,输出到此时为止的中位数。 中位数定义:如果数串的大小是偶数 2j,中位数是从小到大排列的第 j 个数;如果数串的大小是奇数 2j+1,...
  • u011606714
  • u011606714
  • 2016-04-10 00:43:34
  • 1409

算法----中位数算法的妙用(更新中)

部分背包问题: 一个窃贼去一家商店偷窃,有n件商品: 第i件物品值Vi元,重wi榜(vi, wi都是整数),他的背包最多只能装下W榜物品, 每件商品他可以选择一部分带走,而不是像0-1背包问题。问他最...
  • u012653791
  • u012653791
  • 2013-11-07 20:40:54
  • 3630

【leetcode4】用分治算法计算中位数问题

此题在leetcode中评级为hard,目的是在O(log(m+n))的时间复杂度情况下解决问题。用常规O(m+n)的算法很容易求得结果,但 显然不符合时间复杂度的要求。因此,这道题的解题分析主要还...
  • codekiller_
  • codekiller_
  • 2017-03-11 15:48:15
  • 1466

算法导论9-2 邮局位置问题的带权中位数解法证明

d)我用autocad做了一个示意图,如下 以上说明了带权中位数使和式最小,是一维邮局位置问题的最佳解决方案。 e) 可以分别求出x轴、y轴对应点距的带权中位数,然后该坐标点对应的点...
  • crasyangel
  • crasyangel
  • 2013-08-27 00:54:30
  • 2074

找中位数问题——分治法

题目:设A和B都是从小到大已经排好序的n个不等的整数构成的数组, 如果把A与B合并后的数组记作C,设计一个算法找出C的中位数。 解题思路: 思路一: 对将A和B合并数组成C,并且进行排序,然后直接...
  • TommyZht
  • TommyZht
  • 2015-05-29 16:25:53
  • 2439
    个人资料
    等级:
    访问量: 204
    积分: 60
    排名: 156万+
    文章分类
    文章存档