您的位置:首页 > 其它

利用递归求最大子序列

2016-04-13 23:05 288 查看
对于一个序列A1,A2,…….An,求其最大子序列.利用普通的循环来做的话,所花费的时间有点大,便考虑用递归,但递归的缺点也很明显,用空间换时间.但本题也是用于学习递归的比较好的一个例子

e.g.

前半部分后半部分
4 -3 5 -2-1 2 6 -2
我们对这个序列进行切分,最长序列出现的位置有三个,前半部分,后半部分或者横跨两部分. 横跨前后两部分的话,这个序列至少得包含前一个序列的最后一个元素与后半部分的第一个元素.

前半部分的最大值是 6, 后半部分最大值为 8, 横跨两部分的话,最大值为11.所以我们可以得出最大自序列产生于A1~A7

但仔细观察一下,既然一个完整的序列要切成前后两部分,那对于前后两部分,我们还可以再进一步的划分

前半部分后半部分
4 -35 -2-1 26 -2
同理,不断的划分下去,最后可以划分为单个单个的元素.

对于这些元素,他们便是最大值,我们只需要比较这两个元素(
a[left]
and
a[right]
)以及他们的和
(a[left]+a[right]
),找出一个最大值(max),该最大值又是下一次对比的
a[left]
或者
a[right]
元素.

对于这些划分与取值,当取到最后一个时,即
left==right
时,便可以返回该元素,使其等于 maxleftsum 或 rightmaxsum.书上的代码对小于0的情况一律返回0,个人觉得不大喜欢,便修改一下,使其直接返回该元素.这样即使全是负数,也可以求得最大值.

当递归到单个元素返回之后,便可以对横跨前后部分的序列进行求值.利用两个for循环,分别从center向left和right方向进行循环,记录其中最大值
maxleftbordersum
maxrightbordersum
之后记录他们的和便是横跨前后部分的最大值.

以下为代码部分:

int maxsubsum (int a[], int left, int right)
{
int maxleftsum, maxrightsum;
int maxleftbordersum, maxrightbordersum;
int leftbordersum, rightbordersum;
int center, i;

if (left == right)
return a[left];

center = (left+right) / 2;
maxleftsum = maxsubsum(a, left, center);
maxrightsum = maxsubsum(a, center+1, right);

leftbordersum = 0;
maxleftbordersum = a[center];
for (i = center; i >= left; i--)
{
leftbordersum += a[i];
if (leftbordersum > maxleftbordersum)
maxleftbordersum = leftbordersum;
}

rightbordersum = 0;
maxrightbordersum = a[center+1];
for (i = center+1; i <= right; i++)
{
rightbordersum += a[i];
if (rightbordersum > maxrightbordersum)
maxrightbordersum = rightbordersum;
}

return max3 (maxleftsum, maxrightsum, maxleftbordersum+maxrightbordersum);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息