1、问题描述
设X[ 0 : n - 1]和Y[ 0 : n – 1 ]为两个数组,每个数组中含有n个已排好序的数。找出X和Y的2n个数的中位数。 利用分治策略试设计一个O (log n)时间的算法求出这2n个数的中位数。由文件input.txt提供输入数据。文件的第1行中有1个正整n(n<=200),表示每个数组有n个数。接下来的两行分别是X,Y数组的元素。程序运行结束时,将计算出的中位数输出到文件output.txt中。
2、基本思想
①先输入数组x与y并且保存到文件中;
②如果每个数组只有一个元素,直接将这俩个数取平均即为中位数;如果元素个数都为2,那么直接求出中位数;如果不满足以上条件,则找出数组x与数组y的中位数,如果俩个中位数相等,则最后的结果就是这个中位数;如果不相等,就比较大小,如果x比y的中位数大,那么取x的左半部分,y的右半部分;如果x比y的中位数小,那么取x的右半部分,y的左半部分,递归调用这个函数,直到结束;
③输出中位数并且保存到文件中。
3、算法
//设X[ 0 : n - 1]和Y[ 0 : n – 1 ]为两个数组,每个数组中含有n个已排好序的数。找出X和Y的2n个数的中位数。
#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
double findOneMiddle(int x[],int left,int right)//找出数组x的中位数
{
double mid;
int n = right - left + 1;
if (n % 2 == 0)//数组x的个数为偶数
{
mid = (x[n / 2] + x[n / 2 - 1])*0.1 /2;
}
else//数组x的个数为奇数
{
mid = x[n / 2] * 0.1;
}
return mid;
}
int max(int a, int b)//返回max值
{
if (a >= b)
return a;
else
return b;
}
int min(int a, int b)//返回min值
{
if (a >= b)
return b;
else
return a;
}
double findmin(int x[], int y[], int xleft, int xright, int yleft, int yright)
{
double xmid, ymid, mid;
if (xright - xleft == 0)//如果每个数组只有一个元素
return (x[xleft] + y[yleft])*0.1 / 2;
xmid =findOneMiddle(x, xleft, xright);
ymid =findOneMiddle(y, yleft, yright);
if (xmid == ymid)
{
return xmid * 0.1;
}
//只有两个元素,也可以直接计算出两数组中位数
if ((xright - xleft) == 1 && (xright - xleft) == 1)
{
return (max(x[xleft], y[yleft]) + min(x[xright], y[yright]))*1.0 / 2;
}
else if (xmid > ymid)//取x的左半部分,y的右半部分
{
if ((xright - xleft + 1) % 2 == 0)
{
mid = findmin(x, y,xleft, (xright - xleft) / 2+xleft,(yleft + yright) / 2 + 1, yright);
}
else
{
mid =
findmin(x, y, xleft, (xright - xleft) / 2+xleft, (yleft + yright) / 2 , yright);
}
}
else if (xmid < ymid)//取y的左半部分,x的右半部分
{
if ((xright - xleft + 1) % 2 == 0)
{
mid =
findmin(x, y, (xleft + xright)/2+1, xright , yleft, (yleft + yright) / 2+yleft);
}
else
{
mid =
findmin(x, y, (xleft + xright)/2 , xright, yleft, (yleft + yright) / 2+yleft);
}
}
return mid;
}
int main()
{
int n=0, x[200],y[200], i;
double mid;
FILE *fp;
if ((fp = fopen("d:\\input.txt", "w")) == NULL)
{
printf("Can't open the file");
return 0;
}
printf("请输入数组的长度:\n");
fscanf(stdin, "%d", &n);
fprintf(fp, "%d", n);
fprintf(fp, "\n");
printf("请输入数组x:\n");
for (i = 0; i < n;i++)
{
fscanf(stdin, "%d", &x[i]);
fprintf(fp, "%d ", x[i]);
}
fprintf(fp, "\n");
printf("请输入数组y:\n");
for (i = 0; i < n;i++)
{
fscanf(stdin, "%d", &y[i]);
fprintf(fp, "%d ", y[i]);
}
fprintf(fp, "\n");
mid = findmin(x,y, 0, n - 1, 0, n - 1);
fclose(fp);
FILE *fd;
if ((fd = fopen("d:\\output.txt", "w")) == NULL)
{
printf("Can't open the file");
return 0;
}
printf( "中位数为%.1lf\n", mid);
fprintf(fp, "中位数为%.1lf", mid);
fprintf(fp, "\n");
}
或者这样写也可以,代码比上面的简洁
//设X[ 0 : n - 1]和Y[ 0 : n – 1 ]为两个数组,每个数组中含有n个已排好序的数。找出X和Y的2n个数的中位数。
#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
double findmin(int x[], int y[], int x_low, int x_high, int y_low, int y_high)
{
int x_mid, y_mid;
x_mid = (x_low + x_high) / 2;
y_mid = (y_low + y_high) / 2;
if (x_low == x_high)
return ((x[x_low] + y[y_low])*1.0/2);
if ((x_low + x_high) % 2 == 0)
{
if (x[x_mid] > y[y_mid])
{
x_high = x_mid;
y_low = y_mid;
}
else if (x[x_mid] < y[y_mid])
{
x_low = x_mid;
y_high = y_mid;
}
else
return x[x_mid];
}
else
{
if (x[x_mid] > y[y_mid])
{
x_high = x_mid;
y_low = y_mid + 1;
}
else if (x[x_mid] < y[y_mid])
{
x_low = x_mid + 1;
y_high = y_mid;
}
else
return x[x_mid];
}
return findmin(x, y, x_low, x_high, y_low, y_high);
}
int main()
{
int n = 0, x[200], y[200], i;
double mid;
FILE *fp;
if ((fp = fopen("d:\\input.txt", "w")) == NULL)
{
printf("Can't open the file");
return 0;
}
printf("请输入数组的长度:\n");
fscanf(stdin, "%d", &n);
fprintf(fp, "%d", n);
fprintf(fp, "\n");
printf("请输入数组x:\n");
for (i = 0; i < n; i++)
{
fscanf(stdin, "%d", &x[i]);
fprintf(fp, "%d ", x[i]);
}
fprintf(fp, "\n");
printf("请输入数组y:\n");
for (i = 0; i < n; i++)
{
fscanf(stdin, "%d", &y[i]);
fprintf(fp, "%d ", y[i]);
}
fprintf(fp, "\n");
mid = findmin(x, y, 0, n - 1, 0, n - 1);
fclose(fp);
FILE *fd;
if ((fd = fopen("d:\\output.txt", "w")) == NULL)
{
printf("Can't open the file");
return 0;
}
printf("中位数为%.1lf\n", mid);
fprintf(fp, "中位数为%.1lf", mid);
fprintf(fp, "\n");
}