今天我们讨论的算法是最大子数组问题。
首先我定义了一个类用来保存最大子数组的开始位置索引、结束位置索引和该数组的和。代码如下:
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; } };
该算法采用分治策略,我们先讨论最大子数组跨越中点位置的情况:
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; }
接下来是二分法求最大子数组:
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; }
注意:
该书中的伪代码并没有以下这段
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; }
该算法的时间复杂度为θ(nlogn)