用分治法找俩个等长数组的中位数问题

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");
}
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值