算法:动态中位数问题

题目描述

输入一组整数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;
        }
}
阅读更多

没有更多推荐了,返回首页