题目描述
输入一组整数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;
}
}