我试图了解以下算法是如何工作的。
#include <iostream>
using namespace std;
int maxsimum(int a[], int l, int r) {
if (l == r)
return a[l];
int m = (l+r)/2;
int u = maxsimum(a,l,m);
int v = maxsimum(a,m+1,r);
return u>v?u:v;
}
int main() {
int a[] = {34,23,45,56,30,31,57,33,55,10};
int n = sizeof(a)/sizeof(int);
cout << maxsimum(a,0,n) << endl;
return 0;
}
首先,我感兴趣的是,尽管算法工作正常,但它如何找到最大元素对我来说很神秘。我将展示我是如何理解这个算法的:
Step 1: we say that in case of an array, l=0
and r=10
, it checks if (l>r)
which does not hold of course so it calculates m=(0+10)/2;
.然后再次执行新边界的过程。第一对是 (0,5),第二对是 (6,10),在最后的操作之后,它比较两个返回值,最后返回它们之间的最大元素。
这个算法总是有效吗?在每次迭代中,它不做任何比较,只做最后一步。它如何确定每次递归迭代的最大元素?它只检查什么。例如:取pair(0,5),是(0大于5)吗?不,所以再次重复并将这些边界一分为二,得到新的平均值 m1=(0+5)/2 然后再次返回一些元素,但不是最大值。对于第二个子数组,我们也可以这么说。
这个算法的主要思想是什么?
原文由 user466534 发布,翻译遵循 CC BY-SA 4.0 许可协议
你的困惑是可以理解的:所写的算法包含几个错误。它在 a 的末尾访问内存,这是非常非常糟糕的。此外,测试一个范围是否只包含一个元素是不正确的。如果不解决,这会导致堆栈溢出。
调用最大值函数的方式表明下限包含在范围内,但上限不包含在内。
a[0]
是有效的,但是a[n]
访问的内存超过了 a 的末尾。分割范围时,我们希望第一部分从 l 到但不包括 m,第二部分从 m 开始,直到但不包括 r。换句话说:第一部分的“独占”上限等于第二部分的“包含”下限。对 maxsimum 的第一次内部调用是正确的。第二个内部调用应该是:这给我们留下了检测长度为 1 的范围的问题。就目前而言,该算法实际上是在寻找一个 空 范围。正确的测试是查看上限和下限之间的差异:
完整的功能如下:
现在我们有了一个正确的程序,它是如何工作的解释很简单: