成员:林彦汝、张金
题目:
返回一个整数数组中最大子数组的和。
要求:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
如果数组A[0]……A[j-1]首尾相邻,允许A[i-1], …… A[n-1], A[0]……A[j-1]之和最大。
同时返回最大子数组的位置。
求所有子数组的和的最大值。
(我主要负责程序分析,代码编程;张金负责代码复审,代码测试计划。)
思路:
与第一次的不同之处,只在于首尾相连,构成了一个环。思路差不多,我们构造了三个数组:(A)arr[]为原数组;(B)Max[]保存以每个元素为头的所有子数组的和的最大值;(C)arrCopy[]将原数组头尾相连构造的新的一维数组。它们的关系如下:
max[0]为{arr[0]、arr[0]+arr[1]、...、arr[0]+arr[1]+...+arr[n-1]+arr[n]}中的最大值;
max[1]为{arr[1]、arr[1]+arr[2]、...、arr[1]+arr[2]+...+arr[n]+arr[1]}中的最大值;
......
max[n-1]为{arr[n-1]、arr[n-1]+arr[n]、...、arr[n-1]+arr[n]+...+arr[n-3]+arr[n-2]}中的最大值;
max[n]为{arr[n]、arr[n]+arr[1]、...、arr[n]+arr[1]+...+arr[n-2]+arr[n-1]}中的最大值。再比较max数组,从中找到最大值。
arrCopy[]为{arr[1]、arr[2]、...、arr[n]、arr[1]、...、arr[n-1]}这样的一个数组,它的的作用则是标记子数组的位置。
源代码:
#include<iostream.h>
#include<stdlib.h>
#define AMOUNT 100
int main()
{
int arr[AMOUNT];
int arrCopy[AMOUNT];
int max[AMOUNT];
int i,j;
int n;
int head,rear; //子数组的开始,结束
int mount,amount;
cout<<"input mount: ";
cin>>mount;
while(mount<=0)
{
cout<<"illegal input! Again :";
cin>>mount;
}
amount=2*mount-1;
for(i=0;i<mount;i++)
{
try
{
n=rand()%2;
if(n==0)
{
arr[i]=rand()%100;
arrCopy[i]=arr[i];
max[i]=arr[i];
}
else
{
arr[i]=-rand()%100;
arrCopy[i]=arr[i];
max[i]=arr[i];
}
}
catch(long int e)
{
cout<<"Long Inter=ger Exception!"<<endl;
}
}
for(i=0;i<mount;i++)
{
cout<<arr[i]<<" ";
if((i+1)%10==0)
{
cout<<endl;
}
}
for(i=mount;i<amount;i++)
{
arr[i]=arr[i-mount];
arrCopy[i]=arr[i];
}
for(j=0;j<mount;j++)
{
for(i=j+1;i<j+mount;i++)
{
arr[j]=arr[j]+arr[i];
if(max[j]<arr[j])
{
max[j]=arr[j];
rear=i+1;
if(rear>mount)
{
rear=rear-mount;
}
}
}
}
for(i=0;i<mount;i++)
{
if(max[0]<max[i])
{
max[0]=max[i];
head=i+1;
}
}
cout<<endl;
cout<<"从第"<<head<<"个数"<<arrCopy[head-1]<<"开始"<<endl;
cout<<"到第"<<rear<<"个数"<<arrCopy[rear-1]<<"结束"<<endl;
cout<<"子数组和的最大值为: "<<max[0]<<endl;
return 0;
}
运行结果:
(1)首先由于没有仔细的考虑,在提示输入数组长度的时候随意输了负数,导致程序不能正常执行,经过修改,能对不符合的数据类型发出错误提示,并且重新输入。
(2)有图可以看到,定义的数组长度为5,和最大的子数组是由第5个数循环至第1个数组成的,但却显示的是arrCopy[]数组中的第6个数,位置不正确。
在原数组中只有5个数,没有第6个数。要使重复的部分对应到前面部分,要考虑结束位置rear的取值范围,不能超过数组的长度。
(3)经过修改,能正确找到环的结束位置。
(4)但是我们自己手动输入的数都很小,所以最后改动:只输入数组长度(截图测试为10),数值随机产生。
总结:
看到题目最先想到的是数据结构中的链表结构,但是很快就把这个思路放弃,感觉用链表比较麻烦,听了课上三位同学的思路,大家的观点其实都是把数组构成一个环状结构,或者构成一个新的一维数组,接着就跟第一次求最大和一样。开始犯难的是在怎么确定子数组的起始元素和结尾元素上,下标的记录是很关键的,因为在我们的算法中,运用递归会不断覆盖原数组的值,造成所有子数组求完和之后,原数组的值发生了改变,而无法返回最大子数组的位置,既然如此,能像到的方法就是把子数组复制一遍,最后定位时可以使用。最后还是数据测试的问题,手动输入具有很大的主观意识,所以还是使用随机数测试比较能发现问题。
感觉现在能解决一些问题了,但方法还是想初学者那般,很多类似时间、空间复杂度那些都没有考虑。