非常适合递归的问题可以分解为更小、更简单的子问题。这是赋予递归强大功能的原因之一。在尝试使用递归解决问题时,通常最好尝试将问题分解为更简单的子问题以找到解决方案。
您可能会注意到,在查找存储在数组中的最大值 value 时,它要么是第一个元素的值,要么是其余元素的最大值。这将问题分为两部分:如果第一个元素大于任何其余元素,则完成;否则,您必须继续查看下一个元素是否大于其余元素。在代码中,这可能看起来像:
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 的值;请注意,此值是数组中 last 元素的值。然后,当函数返回给它的调用者时,该帧中的max_in_rest 将获得返回值,然后将curr_val 或max_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;
}
只有一点点信息可以跟踪这个时间。在这里,如果满足基本情况,并且rest_sz为1,那么没有理由再看下去,当前索引curr_ndx是最大值的索引。否则,find_max_r() 被递归调用,rest 递增以指向数组的剩余元素,rest_sz 适当递减。这一次,curr_ndx 正在跟踪相对于原始数组的当前索引,并将这个值传递给每个函数调用;此外,指向原始数组第一个元素arr 的指针被传递到每个函数调用中,因此索引值curr_ndx 可以访问原始数组中的值。
同样,当达到基本情况时,数组中的当前位置将是数组的末尾,因此在 return 语句中要比较的第一个元素将朝向数组的末尾,向前移动的数组。注意这里使用>=,而不是>,这样会返回第一个最大值的索引;如果您想要 last 最大值的索引,只需将其更改为 >。
这是一个完整的程序。注意使用辅助函数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