繁体   English   中英

C递归程序查找数组中的最大元素

[英]C recursive program to find the maximum element from array

所以我在训练中有一个听起来像这样的任务:编写一个子程序,它将递归地从数组中找到最大元素,并编写主函数来调用它。 我未能完全理解的是递归是什么。 我想问问你们我的代码是不是递归的。 如果不是,我应该做出什么改变/递归的真正含义是什么?

#include <stdio.h>

int find_maximum(int[], int); 

int main() {
  int c, array[100], size, location, maximum;

  printf("Input number of elements in array\n");
  scanf("%d", &size);

  printf("Enter %d integers\n", size);

  for (c = 0; c < size; c++)
    scanf("%d", &array[c]);

  location = find_maximum(array, size);
  maximum  = array[location];

  printf("Maximum element location = %d and value = %d.\n", location + 1, maximum);
  return 0;
}

int find_maximum(int a[], int n) {
  int c, max, index;

  max = a[0];
  index = 0;

  for (c = 1; c < n; c++) {
    if (a[c] > max) {
       index = c;
       max = a[c];
    }
  }

  return index;
}

谢谢大家的宝贵时间!

不,您的代码不使用递归。 递归是指一个函数调用自身,或调用另一个导致再次调用自身的函数。

您可以像这样更改您的代码以具有递归的、无状态的函数,该函数可以确定数组的最大值。

int find_maximum(int a[], int n) {
   return find_maximum_r(a, 0, n);
} 

int find_maximum_r(int a[], int index, int n) {
  if (index + 1 == n) {
    return a[index];
  }

  int maxRight = find_maximum_r(a, index + 1, n);
  return a[index] > maxRight ? a[index] : maxRight;
}

考虑将数组中的最大数计算为第一个元素的最大值和数组其余元素的最大值。 类似于:max(first_elem, max(remaining_elems))。

实际的递归函数: find_max非常简单,如果数组中只有一个元素,则返回该元素。 否则,我们将获得数组的第一个元素和其余元素中的最大值。

#include <stdio.h>

// function to find the max of 2 numbers
int max(int x, int y)
{
    return (x > y) ? x : y;
}

// the recursive function
int find_max(int *p, int n)
{
    if (n == 1) return *p;

    return max(*p, find_max(p + 1, n - 1));
}

int main(void)
{
    int arr[] = {23, 3, 11, -98, 99, 45};
    printf("max: %d\n", find_max(arr, sizeof arr / sizeof arr[0]));
}

非常适合递归的问题可以分解为更小、更简单的子问题。 这是赋予递归力量的因素之一。 当尝试使用递归来解决问题时,通常最好尝试将问题分解为更简单的子问题以寻找解决方案。

您可能会注意到,在查找存储在数组中的最大值时,它要么是第一个元素的值,要么是其余元素的最大值。 这将问题分为两部分:如果第一个元素比任何剩余元素都大,你就完成了; 否则,您必须继续查看下一个元素是否大于其余元素。 在代码中,这可能看起来像:

int max_in(size_t rest_sz, int *rest)
{
    int curr_val = rest[0];
    if (rest_sz == 1) {
        return curr_val;
    }

    int max_in_rest = max_in(rest_sz-1, rest+1);

    return curr_val > max_in_rest ? curr_val : max_in_rest;
}

这里有一个基本情况:如果rest_sz为 1,则无需进一步查看; 第一个元素 ( curr_val = rest[0] ) 的值是最大值,并返回该值。 如果不满足基本情况,则继续执行函数。 max_in_rest是递归函数调用max_in(rest_sz-1, rest+1)的结果。 这里rest_sz-1表示rest+1指示的数组部分中剩余的元素数。 在新的函数调用中,基本情况再次得到满足,最终这种情况将成立,因为rest_sz会随着每次递归调用而递减。 发生这种情况时,将返回当前堆栈帧中curr_val的值; 请注意,此值是数组中最后一个元素的值。 然后,当函数返回给它的调用者时,该帧中的max_in_rest将获得返回值,之后将curr_valmax_in_rest中较大的返回给前一个调用者,依此类推,直到最终控制权返回给main()

使用铅笔和纸绘制每个函数调用、其变量的值以及返回的内容将有助于准确理解此递归的工作原理。

您可以应用相同的方法来解决查找数组最大值索引的问题。 在这种情况下,如果第一个元素的值大于任何剩余元素的值,则最大元素的索引是第一个元素的索引; 否则最大元素的索引是剩余元素的最大值的索引。 在代码中,这可能看起来像:

size_t find_max_r(int arr[], int *rest, size_t rest_sz, size_t curr_ndx)
{
    if (rest_sz == 1) {
        return curr_ndx;
    }

    int curr_val = arr[curr_ndx];
    size_t max_in_rest_ndx = find_max_r(arr, rest+1, rest_sz-1, curr_ndx+1);
    int max_in_rest = arr[max_in_rest_ndx];

    return curr_val >= max_in_rest ? curr_ndx : max_in_rest_ndx;
}

这次只有一点点信息可以跟踪。 这里,如果满足base case,并且rest_sz为1,那么就不用再往下看了,当前索引curr_ndx就是最大值的索引。 否则,递归调用find_max_r()rest递增以指向数组的剩余元素,并且rest_sz适当递减。 这一次, curr_ndx跟踪相对于原始数组的当前索引,并将该值传递给每个函数调用; 此外,指向原始数组第一个元素arr的指针被传递到每个函数调用中,因此索引值curr_ndx可以访问原始数组中的值。

同样,当达到基本情况时,数组中的当前位置将是数组的末尾,因此 return 语句中要比较的第一个元素将朝向数组的末尾,移向数组的前面. 注意这里使用了>= ,而不是> ,这样返回的是第一个最大值的索引; 如果您想要最后一个最大值的索引,只需将其更改为>即可。

这是一个完整的程序。 请注意辅助函数find_max()调用递归函数find_max_r()的使用,它允许调用者使用具有与发布代码使用的相同签名的函数(除了使用size_t类型,这确实是正确的数组索引的类型):

#include <stdio.h>

int max_in(size_t sz, int *rest);
size_t find_max(size_t sz, int arr[]);
size_t find_max_r(int arr[], int *rest, size_t rest_sz, size_t curr_ndx);

int main(void)
{
    int array[] = { 2, 7, 1, 8, 2, 5, 1, 8 };
    size_t array_sz = sizeof array / sizeof array[0];

    int max_val = max_in(array_sz, array);
    printf("Maximum value is: %d\n", max_val);

    size_t max_ndx = find_max(array_sz, array);
    printf("Maximum value index: %zu\n", max_ndx);

    return 0;
}

int max_in(size_t rest_sz, int *rest)
{
    int curr_val = rest[0];
    if (rest_sz == 1) {
        return curr_val;
    }

    int max_in_rest = max_in(rest_sz-1, rest+1);

    return curr_val > max_in_rest ? curr_val : max_in_rest;
}

size_t find_max(size_t sz, int arr[])
{
    int *rest = arr;
    return find_max_r(arr, rest, sz, 0);
}

size_t find_max_r(int arr[], int *rest, size_t rest_sz, size_t curr_ndx)
{
    if (rest_sz == 1) {
        return curr_ndx;
    }

    int curr_val = arr[curr_ndx];
    size_t max_in_rest_ndx = find_max_r(arr, rest+1, rest_sz-1, curr_ndx+1);
    int max_in_rest = arr[max_in_rest_ndx];

    return curr_val >= max_in_rest ? curr_ndx : max_in_rest_ndx;
}

程序输出:

Maximum value is: 8
Maximum value index: 3

不,仅当您直接或间接从自身调用函数find_maximum时,您的代码才是递归的。

由于您的函数不仅要获取最大值,还要获取数组中的位置,因此我稍微修改了接口以返回引用(即指向值的指针),因此我们可以推断出数组的位置元素直接减去元素指针。 这样,我可以直接将数组指针和数组大小传递给函数,然后将数组分成两半,并对两半应用相同的函数(可以证明如果某个元素是最大值数组,它必须大于或等于每一半的最大值)出于同样的原因,我修改了main()函数中定义的一些变量,以允许使用引用:

最大c

#include <stdio.h>
#include <assert.h>

int *find_maximum(int a[], int n); /* return a reference pointer to the maximum value */

int main() {
  int c, array[100], size, *location, /* location must be a pointer */
  maximum;

  printf("Input number of elements in array\n");
  scanf("%d", &size);
  assert(size >= 1);

  printf("Enter %d integers\n", size);

  for (c = 0; c < size; c++)
    scanf("%d", &array[c]);

  location = find_maximum(array, size);
  maximum  = *location; /* access to the value is granted by pointer dereference */
  printf("Maximum element location = %td and value = %d.\n", 
         location - array, /* pointer difference gives the array position */ 
         maximum);
  return 0;
} /* main */

/* somewhat efficient recursive way of a divide and conquer method 
 * to get the maximum element reference. */
int *find_maximum(int a[], int n)
{
    if (n == 1) return a; /* array of 1 element */
    int *left  = find_maximum(a,       n/2), /* left half begins at a
                                              * and has n/2 elements */
        *right = find_maximum(a + n/2, (n+1)/2); /* right half begins 
                                                  * at a + n/2, and
                                                  * has (n+1)/2 
                                                  * elements */
    return *left > *right 
           ? left 
           : right;
} /* find_maximum */

如您所见,我必须除以二,但由于我有任意长度的数组,我必须小心不要在下一步遗漏任何元素。 这就是在函数递归调用的右半部分使用(n+1)/2元素数组的原因。 我在前半部分包含n/2元素(向下舍入),我必须在右半部分包含(n+1)/2元素(向上舍入),以确保我在两半中包含所有数组元素.

首先,递归意味着——函数调用自身。

在此处输入图像描述

你写的不是递归函数。 我将发布使用递归查找数组中最大或最大元素的最简单方法。

#include<stdio.h>  
  
#define N 5  
  
int biggest(int num[], int n, int big)  
{  
    if(n < 0)  
        return big;  
    else  
    {  
        if(big < num[n])  
            big = num[n];  
  
        return biggest(num, --n, big);  
    }  
}  
  
int main()  
{  
    int a[N], i;  
  
    printf("Enter %d integer number\n", N);  
    for(i = 0; i < N; i++)  
        scanf("%d", &a[i]);  
  
    printf("Biggest Element in the array: %d\n", biggest(a, N - 1, a[0]));  
  
    return 0;  
} 

在此处输入图像描述

资料来源: 使用递归查找数组最大元素的 C 程序

NO 这不是递归函数

要了解递归,此链接非常有用https://www.khanacademy.org/computing/computer-science/algorithms/recursive-algorithms/a/recursion/

做一个递归函数来解决你的问题试试这个

你可以试试这个伪代码声明你的数组全局和 max=0 全局和大小全局

int find_maximum(int i)
{
if (i == size )
    return max;
else if ( max < array[i])
    max =array [i];
return find_maximum(i+1);
}

其中 i 是数组索引

不,你的程序肯定不是递归的。 根据定义,递归函数必须以终止条件调用自身。

请阅读 TutorialsPoint 关于 C 中的递归

@JonathanLeffler 评论的更新:请注意参考中的输出会溢出。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM