关于最大子数组问题的讨论

问题描述:即求数组中和最大的连续子数组


方法一:分治法

将数组A以mid为界分成左右两个相同大小的子数组,则任一子数组在A[0..mid]、A[mid+1..A.length]和跨过mid,两端分别在[0..mid]和[mid+1..A.length]中;这3种情况之一

 依据这个可以设计递归方法,其中最重要的是:

1、分别从mid向左寻找和最大的点i,从mid+1向右寻找和最大的点j,则A[i..j]即为跨过中点的最大子数组

2、最后选择左,中,右3者中的最大子数组和最大的返回

typedef struct sum_str{//定义一个结构体便于传参
	int start;
	int end;
	int sum;
}str_sum;

void getmax_divide(int * A,str_sum *p){//分治法
	//通过p传进来start和end,传回去最大子数组的start,end,sum,这样避免了动态内存分配
	if(p->start>=p->end){
		p->sum=A[p->start];
		return;
	}

	int mid=(p->start+p->end)/2;

	str_sum left={p->start,mid,0};//左边的递归调用[0..mid]
	getmax_divide(A,&left);

	str_sum right={mid+1,p->end,0};//右边的递归调用[mid+1..end]
	getmax_divide(A,&right);

	int i,tep,maxsum_left,maxsum_right,sum=0;//下面计算穿过mid的最大子数组

	for (i=mid+1,tep=i,maxsum_right=A[i],sum=0;i<=p->end;i++){//从mid+1向右遍历,记录最大子数组
		sum+=A[i];
		if(maxsum_right<sum){
			tep=i;
			maxsum_right=sum;
		}
	}
	p->end=tep;

	for (i=mid,tep=i,maxsum_left=A[i],sum=0;i>=p->start;i--){//从mid向左遍历,记录最大子数组
		sum+=A[i];
		if(maxsum_left<sum){
			tep=i;
			maxsum_left=sum;
		}
	}
	p->start=tep;

	p->sum=maxsum_left+maxsum_right;//左右的sum加在一起,为穿过mid的最大子数组

	str_sum *t;
	if(p->sum>=left.sum && p->sum>=right.sum){//选出3者中最大的返回去
		return;
	}else if(left.sum>=right.sum && left.sum>=p->sum){
		t=&left;
	}else t=&right;

	p->start=t->start;
	p->end=t->end;
	p->sum=t->sum;
}



这里有T(n)=2*T(n/2)+Θ(n)  =>   T(n)=Θ(n*lgn)   注:这里lgn为log(2)(n)


方法二、动态规划

int getmax_dynamic(int * A,int n){//动态规划中的方法
	int maxsum=A[n-1];
	int st=n-1,ed=n-1,tep=n-1;

	int sum=0;
	

	while(--n>=0){
		sum+=A[n];

		if(sum>maxsum){
			maxsum=sum;
			st=n;
			ed=tep;
		}
		if(sum<0){
			sum=0;
			tep=n-1;
		}
	}

	cout << st <<":"<<ed<<":"<<maxsum<<endl;
	return maxsum;
}


最后利用随机数方法对两个方法测试:

void init(int *a,int &n){//初始化数组的数据,用于测试
	srand(n);

	do{
	n=int(rand()%len)+1;
	}while(!n);

	int i=0;
	
	for (i=0;i<n;i++){
		a[i]=rand()%span-span/2;
	}
}


int main(){
	int n=0;
	int A[len];

	/*
	cout<<"input n:";

	n=0;
	while(cin>>A[n]) n++;

	if(n<=0) return 0;
    */

	while(1){
		init(A,n);

		cout << endl << "********************************************************************\n";
		for (int i=0;i<n;i++)
			cout << A[i] << " ";
		cout <<endl << n <<endl;

		int kepp=getmax_dynamic(A,n);

		str_sum t={0,n-1,0};
		getmax_divide(A,&t);
		cout<<t.start<<":"<<t.end<<":"<<t.sum<<endl;

		if(t.sum!=kepp) break;//当两种方法结果不同时就表示有一个出错了
	}

return 0;
}

完整的代码文件为:http://download.csdn.net/detail/haohaohaoxu/9753563

不足之处欢迎指正。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值