关于分治递归的具体细节

    ***

标题:关于分治递归求最大连续字串的具体实现


目录)


前言

``在我学习数据结构与算法(c版本)这本书中,我遇见一个棘手的问题,--数组中求连续最大子序列和--,相信不少人在leetcode中遇见或做过,书中给出的算法是分治递归,代码本身简洁明了,但背后的底层逻辑曾令我苦恼许久,查了很多资料都是介绍其思想,而其中最关键的递归细节却没有谈到,我直到近日才有点眉目,因此也想写篇博客来巩固一下。


``

一、简单回顾问题-分治思想

话说有这么一个数组A**[ ] = {4, -3, 5, -2, -1, 2, 6, -2};** 我们需要利用一个算法求出其中一个最大字序列之和,要求是连续且不能为0。****
如果我们一个个推算可知结果为11=( A[0]到A[6] ), 但如何用程序写出来尼?
于是我们给出分治递归算法,简而言之就是将上面的8个数先一分为二,得到一组数为{4,-3,5,-2},另一组为{-1,2,6,-2};之后继续一分为二直到不可再分-即得到单个数字,这样做有什么用呢? 我们拿其中一组{4,-3}来举例,所谓最大子序列无非在三个位置:1.都在左边 42.都在右边(-3)3.中间-1(4 + (-3))
于是乎我们将这三个位置的数进行比较大小,最大的那个子序列就是我们想要的,然后我们依次将情况往前推算,得到整个数组的最大连续子序列,当然对于单个数来说其本身就是最大子序列。

二、分治的实现

我们想要实现分治的思想就不得不借助递归语句,遗憾的是书中的程序递归是如此复杂,递归深度如此之深让人望而生畏。在经过许久的思考与调试之后我完整的过了一遍细节,下面我先将书中程序放在下面让大家思考
`
#include<stdio.h>

int Max3(int a, int b, int c)
{
if (a > b && a > c)
return a;
else if (b > a && b > c)
return b;
else if (a == c && a > b)
return a;
else
return c;
}

static int MaxSubSum(const int A[], int Left, int Right )
{
int MaxLeftSum, MaxRightSum;
int MaxLeftBorderSum, MaxRightBorderSum;
int LeftBoardSum, RightBorderSum;
int Center, i;

if (Left == Right)
	if (A[Left] > 0)
		return A[Left];
	else
		return 0;

Center = (Left + Right) / 2;

MaxLeftSum = MaxSubSum(A, Left, Center);     // 递归关键1 ,左边
MaxRightSum = MaxSubSum(A, Center + 1, Right);// 递归关键2 , 右边

MaxLeftBorderSum = 0;  LeftBoardSum = 0;  // 3
for (i = Center; i >= Left; i--)           
{
	LeftBoardSum += A[i];
	if (LeftBoardSum > MaxLeftBorderSum)
		MaxLeftBorderSum = LeftBoardSum;
}

MaxRightBorderSum = 0; RightBorderSum = 0;
for (i = Center + 1; i  <=  Right; i++)
{
	RightBorderSum += A[i];
	if (RightBorderSum > MaxRightBorderSum)
		MaxRightBorderSum = RightBorderSum;
}                                    //4   从3到4是为得到中间子序列和
return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );

} //比较这三个位置的大小

int main()
{
int A[8] = { 4, -3, 5, -2, -1, 2, 6, -2 };

printf( "%d", MaxSubSum(A, 0, 7) );

return 0;

}

在主函数中我们第一次调用函数然后进入函数MaxSubSum中然后走到关键1这一步进行递归直到遇见基准情形,这些递归是容易理解的,因为他们都属于自已调用自已的例程,如图在这里插入图片描述在这里插入图片描述

另外需要注意的是,当递归返回上一级的时候,若此时下面还有其他代码时,则会先执行下面代码随后再返回上一级

在这里插入图片描述

例**如递归深度为3的函数返回上一级,并将返回的数赋值给深度为2函数中的MaxLeftSum,然后继续执行下面的代码。请注意:此时递归深度为2且又将执行关键2的递归嵌套,这将带来令人恐惧的逻辑!
在这里插入图片描述
在这里插入图片描述
由于篇幅原因,两幅图的步骤可能不一致,相差一步或两步。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
剩下过程请读者自行推算,因为如果不自已推演几遍,是无法真正理解的。不过我仍将最后的完整途径给出来以便大家对照
在这里插入图片描述
(请读者观察一下每列相似的地方,这会有助你对程序的理解)

值得注意的是你需要明白递归返回上一级是在哪个地方,因为可能下一步可能又是一个递归。

总结细心的朋友可能会发现这里的递归不像我们初学的那样是线性的,换句话说不像图上最上面那一行一路走到底然后一路返回上一级,因为这不是一个尾递归而且这两个递归会相互嵌套!
现在我们来剖析一下程序的本质:被一直平分直到无法再分的每个子序列都需要确定两个数,一个LeftSubSum,一个RightSubSum;(单独的一个数为它本身,所以你会发现无论递归多么复杂,最终都只会返回两次结果,比如最上面的一行只会返回
LeftSubSum的结果,而往下面那么多复杂的递归目的就是为了得出RightSubSum的结果

但我无论说了多少,都比不过你自已实践一次的效果好,我能做的就是提供思路,如果读者按照我的思路一步步理解每一步的过程,你就会跟我一样惊叹这个程序与算法的神奇与美妙!!!

  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值