在单个递归函数中查找数组的最大值和最小值

时间:2016-02-27 10:17:03

标签: c arrays algorithm recursion

以下程序使用Divide and Conquer范例,并使用Merge Sort的思想以递归方式查找数组的最大和最小元素。这是一个要求递归执行的任务,我编写了解决方案,但我的问题是它是否最小化了查找最小值和最大值所需的比较次数?

#include <stdio.h>
#include <limits.h>


void max(int *ptr, int lower, int upper, int *maximum, int *min)
{
  //returns the maximum element of the array
  int mid;
  int left, right;

  if(lower == upper){
    if(ptr[lower] > *maximum)
      {
         *maximum = ptr[lower];
      }
    if(ptr[lower] < *min)
      {
         *min = ptr[lower];
      }
    return;
  }

  mid = (lower+upper) /2;

  max(ptr, lower, mid, maximum, min);
  max(ptr, mid+1, upper, maximum, min);
}

int main()
{
  int n;
  int i;

  int *ptr;

  int maximum=-1;
  int minimum=INT_MAX;


  printf("\nEnter the size of the array : ");
  scanf("%d", &n);

  ptr = (int *) malloc(sizeof(int)*n);

  printf("Enter the contents of the array : ");

  for(i=0 ; i<n; i++)
    scanf("%d", &ptr[i]);

  max(ptr,0,n-1,&maximum,&minimum);

  printf("\n Maximum element is : %d", maximum);
  printf("\n Minimum element is : %d", minimum);

  free(ptr);

  return 0;
}

3 个答案:

答案 0 :(得分:2)

使用else来最小化比较。如果你找到一个新的最大值,那么它不能是最小值(或者如果你想要的话,反之亦然):

if (ptr[lower] > *maximum) {
  *maximum = ptr[lower];
} else {
  if (ptr[lower] < *min) {
    *min = ptr[lower];
}

为此,您需要将min和max初始化为数组中的任何值:

minimum = maximum = ptr[0];

请注意,在您的情况下,递归模式是绝对无用的,对数组进行简单的增量解析就足够了,可以节省大量的操作(计算中间,测试基本情况,传递参数,函数)调用)。另一种方法是在扫描输入时计算结果......

答案 1 :(得分:2)

  

是否可以最大限度地减少查找所需的比较次数   最小值和最大值?

简答:否

您的代码实际需要

n * 4 - 1

比较,其中n是数组中的项目数。

以上计算1比较以检查lower==upper,如果它评估了真正的2个比较以检查maxmin

如果您只是使用for循环从开头到结尾解析数组,那么

n * 2

比较

但是等一下:因为你还需要在每次迭代时都有一个for循环,还有一个额外的比较来检查循环是否结束。

所以实际上有

n * 3

比较

您发布的代码效率不高,此外,您必须在每次调用mid时计算max()以及递归函数调用的开销。

由于你有一个无序的数组或数字,你必须找到最小和最大的解决方案(正如其他人指出的那样)迭代数组。

如果你想要一个证明,你可以测试它......

这是输出:

Elements count : 10000
Maximum element is : 99964
Minimum element is : 9
Number of comparisons : 39999

以下是嵌入测试的代码

(我刚刚添加了一个在每次比较之前递增的全局g_comparisons - 也是以编程方式使用随机值完成数组填充的过程)

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int g_comparisons = 0;

void max(int *ptr, int lower, int upper, int *maximum, int *min)
{
    //returns the maximum element of the array
    int mid;
    g_comparisons ++;
    if(lower == upper){
        g_comparisons += 2;
        if(ptr[lower] > *maximum)
        {
            *maximum = ptr[lower];
        }
        if(ptr[lower] < *min)
        {
            *min = ptr[lower];
        }
        return;
    }

    mid = (lower+upper) /2;

    max(ptr, lower, mid, maximum, min);
    max(ptr, mid+1, upper, maximum, min);
}

int main()
{
    int n;
    int i;

    int *ptr;

    int maximum=-1;
    int minimum=INT_MAX;


    //printf("\nEnter the size of the array : ");
    //scanf("%d", &n);

    n = 10000;

    ptr = (int *) malloc(sizeof(int)*n);

    // printf("Enter the contents of the array : ");

    for(i=0 ; i<n; i++)
    {
    //    scanf("%d", &ptr[i]);
        ptr[i] = rand()%100000;
    }

    max(ptr,0,n-1,&maximum,&minimum);

    printf("\n Elements count : %d" , n);

    printf("\n Maximum element is : %d", maximum);
    printf("\n Minimum element is : %d", minimum);

    printf("\n Number of comparisons : %d\n", g_comparisons);

    free(ptr);

    return 0;
}

答案 2 :(得分:0)

我想指出两件事 1.如果数组已排序,则查找最小值和最大值需要O(1)时间。 2.如果数组不是按排序顺序排列,那么如果您的目标只是找到最小和最大数字,那么排序对您没有帮助。原因如下:任何基于比较的排序算法都需要Ω(nlogn)时间,而最大值和最小值可以在单个for循环迭代中一起找到。每次比较下一个元素到目前为止发现的最大值和最小值。所以只使用一个for循环。这很简单

如果你的作业强制你以递归方式进行,那么它仍然可以在O(n)比较中完成。简单而不是编写for循环使用recurssion函数,在循环中编写的代码稍作修改。