《算法导论》——MaximumSubArray

  今天我们讨论的算法是最大子数组问题。

  首先我定义了一个类用来保存最大子数组的开始位置索引、结束位置索引和该数组的和。代码如下:

复制代码
class MaximumSubArray
    {
    private:
        int begin;    //开始位置索引
        int end;    //结束位置索引
        int sum;    //
    public:
        void setBegin(int Begin)
        {
            begin=Begin;
        }
        void setEnd(int End)
        {
            end=End;
        }
        void setSum(int Sum)
        {
            sum=Sum;
        }

        int getBegin()
        {
            return begin;
        }
        int getEnd()
        {
            return end;
        }
        int getSum()
        {
            return sum;
        }
    };
View Code
复制代码

  该算法采用分治策略,我们先讨论最大子数组跨越中点位置的情况:

复制代码
MaximumSubArray FindMaxCrossingSubArray(int *numArray,int low,int middle,int high)
    {
        MaximumSubArray max;
        int leftsum=numArray[middle];        
        int maxleft=middle;
        int sum=0;
        for(int i=middle;i>=low;i--)
        {
            sum+=numArray[i];
            if(sum>=leftsum)
            {
                leftsum=sum;
                maxleft=i;
            }
        }
        int rightsum=numArray[middle+1];
        int maxright=middle+1;
        sum=0;
        for(int j=middle+1;j<=high;j++)
        {
            sum+=numArray[j];
            if(sum>=rightsum)
            {
                rightsum=sum;
                maxright=j;
            }
        }
        max.setBegin(maxleft);
        max.setEnd(maxright);
        max.setSum(leftsum+rightsum);
        return max;
    }
View Code
复制代码

  接下来是二分法求最大子数组:

复制代码
MaximumSubArray FindMaximumSubArray(int *numArray,const int low,const int high)
    {
        MaximumSubArray max;
        if(high==low)
        {
            max.setBegin(low);
            max.setEnd(high);
            max.setSum(numArray[low]);
            return max;
        }
        if(high-1==low)
        {
            max.setBegin(high);
            max.setEnd(high);
            max.setSum(numArray[high]);
            return max;
        }
        int middle=(low+high)/2;
        MaximumSubArray left=FindMaximumSubArray(numArray,low,middle);
        MaximumSubArray right=FindMaximumSubArray(numArray,middle,high);
        MaximumSubArray cross=FindMaxCrossingSubArray(numArray,low,middle,high);
        if(left.getSum()>=right.getSum()&&left.getSum()>=cross.getSum())
            max=left;
        else if(right.getSum()>left.getSum()&&right.getSum()>=cross.getSum())
            max=right;
        else
            max=cross;
        return max;
    }
View Code
复制代码

注意:

  该书中的伪代码并没有以下这段

if(high-1==low)
        {
            max.setBegin(high);
            max.setEnd(high);
            max.setSum(numArray[high]);
            return max;
        }

因为在算法递归到数组中只有两个元素的时候,算出的middle值和low值是一样的(& 索引为0和1的两个元素),所以,在high==low的时候去索引小的元素,在high-1=low的时候取索引大的元素,避免无限循环。

以上代码,请放到如下注释的位置,保存为SubArray.h

#include <stdlib.h>

namespace dksl
{
//
//
//
}

  下面是程序测试代码及运行结果:

复制代码
#include "stdafx.h"
#include <iostream>
#include "SubArray.h"

using namespace std;
using namespace dksl;
int _tmain(int argc, _TCHAR* argv[])
{
    int a[16] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};   
    MaximumSubArray max=FindMaximumSubArray(a,0,15);
    cout<<"begin:"<<max.getBegin()<<endl;
    cout<<"end:"<<max.getEnd()<<endl;
    cout<<"sum:"<<max.getSum()<<endl;
    system("PAUSE");
    return 0;
}
View Code
复制代码

该算法的时间复杂度为θ(nlogn)

posted @   Scott Lewis  阅读(295)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示