《算法导论》——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 @ 2013-06-20 23:31  Scott Lewis  阅读(295)  评论(0编辑  收藏  举报