1、T(N)=O(N^3)
__int64 algorithm1(__int64 a[],__int64 n) //T(N)=O(N^3)
{
__int64 MaxSum = 0;
__int64 ThisSum;
for(__int64 i = 0; i < n; i++) //i从零开始到最后一个数字
{
for(__int64 j = i; j < n; j++) //j从i开始到最后一个数字
{
ThisSum = 0;
//PS:第一轮循环k从0->0,0->1,0->2...0->n
//PS:第二轮循环k从1->1,1->2,1->3...1->n
//PS:第K轮循环k从k->k,k->k+1,k->k+2...k->n
//PS:这样就遍历完序列中所有子序列的可能性
for(__int64 k = i; k <= j; k++) //从i开始到j的数字相加
ThisSum += a[k];
if(ThisSum > MaxSum) //大于最大子序列之和则替换
MaxSum = ThisSum;
}
}
return MaxSum;
}
__int64 algorithm2(__int64 a[],__int64 n) //T(N)=O(N^2)
{
__int64 MaxSum = 0;
__int64 ThisSum;
for(__int64 i = 0; i < n; i++) //i从零开始到最后一个数字
{
ThisSum = 0;
//PS:第一轮j从0->n,每循环一次,判断一次
//PS:第二轮j从1->n,每循环一次,判断一次
//PS:第J轮j从j->n,每循环一次,判断一次
//PS:这样就遍历完序列中所有子序列的可能性
for(__int64 j = i; j < n; j++) //j从i开始到最后一个数字
{
ThisSum += a[j];
if(ThisSum > MaxSum) //大于最大子序列之和则替换
MaxSum = ThisSum;
}
}
return MaxSum;
}
PS:用分治法,先将原序列分成相似的两个子序列,这样可以得出一个结论,
那就是最大子序列和要不在左子序列中,要不在右子序列中,要不在左子序列和右子序列的连接处
对左子序列递归求最大序列和,对右子序列求最大序列和,再将左右子序列连接起来,求连接处的最大序列和
最后比较就能求出整体最大序列和
__int64 MaxSubSum(__int64 a[],__int64 Left,__int64 Right)
{
__int64 Center; //中间元素
__int64 MaxLeftSum,MaxRightSum; //左右子序列最大序列和
__int64 MaxLeftBorderSum,MaxRightBorderSum; //左右边界最大序列和
__int64 LeftBorderSum,RightBorderSum; //左右边界序列和
if(Left == Right) //递归出口
if(a[Left] > 0) //当a[i]>0时,返回该元素
return a[Left];
else //否则返回0
return 0;
Center = (Left + Right) / 2;
MaxLeftSum = MaxSubSum(a,Left,Center); //递归求解左子序列
MaxRightSum = MaxSubSum(a,Center + 1,Right); //递归求解右子序列
MaxLeftBorderSum = 0;
LeftBorderSum = 0;
for(__int64 i = Center; i>= Left; i--) //求左边界最大序列和
{
LeftBorderSum += a[i];
if(LeftBorderSum > MaxLeftBorderSum)
MaxLeftBorderSum = LeftBorderSum;
}
MaxRightBorderSum = 0;
RightBorderSum = 0;
for(__int64 i = Center + 1; i <= Right; i++) //求右边界最大序列和
{
RightBorderSum += a[i];
if(RightBorderSum > MaxRightBorderSum)
MaxRightBorderSum = RightBorderSum;
}
return max(max(MaxLeftSum,MaxRightSum),MaxLeftBorderSum+MaxRightBorderSum); //返回整体最大序列和
}
__int64 algorithm3(__int64 a[],__int64 n) //T(N)=O(NlogN),底数为2
{
return MaxSubSum(a,0,n - 1);
}
推荐用这种算法
__int64 algorithm4(__int64 a[],__int64 n) //T(N)=O(N)
{
__int64 ThisSum = 0;
__int64 MaxSum = 0;
for(int i = 0; i < n; i++) //i从零开始到最后一个数字
{
ThisSum += a[i];
if(ThisSum < 0) //当a[j]+...+a[i] < 0,则舍弃i之前的所有序列,从i后继续累加
ThisSum = 0;
if(ThisSum > MaxSum) //求出当前序列的最大子序列和
MaxSum = ThisSum;
}
return MaxSum;
}
5、数量级及其时间比较表格
Algorithm | 1 | 2 | 3 | 4 | |||||
Time | O(N^3) | T/N Rate | O(N^2) | T/N Rate | O(NlogN) | T/N Rate | O(N) | T/N Rate | |
Input Size(N) | 10 | 0.903 | 0.0903 | 0.771 | 0.0771 | 0.734 | 0.0734 | 0.707 | 0.0707 |
100 | 1.069 | 0.01069 | 0.791 | 0.00791 | 0.784 | 0.00784 | 0.744 | 0.00744 | |
1000 | 3.538 | 0.003538 | 0.952 | 0.000952 | 0.805 | 0.000805 | 0.78 | 0.00078 | |
10000 | 3000 | 0.3 | 1.599 | 0.0001599 | 1.067 | 0.0001067 | 0.859 | 0.0000859 | |
100000 | 3000000 | 30 | 73.844 | 0.00073844 | 1.255 | 0.00001255 | 1.125 | 0.00001125 |
6、源代码及其测试数据
#include
#include
#include
#include
using namespace std;
__int64 algorithm1(__int64 a[],__int64 n) //T(N)=O(N^3)
{
__int64 MaxSum = 0;
__int64 ThisSum;
for(__int64 i = 0; i < n; i++) //i从零开始到最后一个数字
{
for(__int64 j = i; j < n; j++) //j从i开始到最后一个数字
{
ThisSum = 0;
//PS:第一轮循环k从0->0,0->1,0->2...0->n
//PS:第二轮循环k从1->1,1->2,1->3...1->n
//PS:第K轮循环k从k->k,k->k+1,k->k+2...k->n
//PS:这样就遍历完序列中所有子序列的可能性
for(__int64 k = i; k <= j; k++) //从i开始到j的数字相加
ThisSum += a[k];
if(ThisSum > MaxSum) //大于最大子序列之和则替换
MaxSum = ThisSum;
}
}
return MaxSum;
}
__int64 algorithm2(__int64 a[],__int64 n) //T(N)=O(N^2)
{
__int64 MaxSum = 0;
__int64 ThisSum;
for(__int64 i = 0; i < n; i++) //i从零开始到最后一个数字
{
ThisSum = 0;
//PS:第一轮j从0->n,每循环一次,判断一次
//PS:第二轮j从1->n,每循环一次,判断一次
//PS:第J轮j从j->n,每循环一次,判断一次
//PS:这样就遍历完序列中所有子序列的可能性
for(__int64 j = i; j < n; j++) //j从i开始到最后一个数字
{
ThisSum += a[j];
if(ThisSum > MaxSum) //大于最大子序列之和则替换
MaxSum = ThisSum;
}
}
return MaxSum;
}
//PS:用分治法,先将原序列分成相似的两个子序列,这样可以得出一个结论,
//那就是最大子序列和要不在左子序列中,要不在右子序列中,要不在左子序列和右子序列的连接处
//对左子序列递归求最大序列和,对右子序列求最大序列和,再将左右子序列连接起来,求连接处的最大序列和
//最后比较就能求出整体最大序列和
__int64 MaxSubSum(__int64 a[],__int64 Left,__int64 Right)
{
__int64 Center; //中间元素
__int64 MaxLeftSum,MaxRightSum; //左右子序列最大序列和
__int64 MaxLeftBorderSum,MaxRightBorderSum; //左右边界最大序列和
__int64 LeftBorderSum,RightBorderSum; //左右边界序列和
if(Left == Right) //递归出口
if(a[Left] > 0) //当a[i]>0时,返回该元素
return a[Left];
else //否则返回0
return 0;
Center = (Left + Right) / 2;
MaxLeftSum = MaxSubSum(a,Left,Center); //递归求解左子序列
MaxRightSum = MaxSubSum(a,Center + 1,Right); //递归求解右子序列
MaxLeftBorderSum = 0;
LeftBorderSum = 0;
for(__int64 i = Center; i>= Left; i--) //求左边界最大序列和
{
LeftBorderSum += a[i];
if(LeftBorderSum > MaxLeftBorderSum)
MaxLeftBorderSum = LeftBorderSum;
}
MaxRightBorderSum = 0;
RightBorderSum = 0;
for(__int64 i = Center + 1; i <= Right; i++) //求右边界最大序列和
{
RightBorderSum += a[i];
if(RightBorderSum > MaxRightBorderSum)
MaxRightBorderSum = RightBorderSum;
}
return max(max(MaxLeftSum,MaxRightSum),MaxLeftBorderSum+MaxRightBorderSum); //返回整体最大序列和
}
__int64 algorithm3(__int64 a[],__int64 n) //T(N)=O(NlogN),底数为2
{
return MaxSubSum(a,0,n - 1);
}
__int64 algorithm4(__int64 a[],__int64 n) //T(N)=O(N)
{
__int64 ThisSum = 0;
__int64 MaxSum = 0;
for(int i = 0; i < n; i++) //i从零开始到最后一个数字
{
ThisSum += a[i];
if(ThisSum < 0) //当a[j]+...+a[i] < 0,则舍弃i之前的所有序列,从i后继续累加
ThisSum = 0;
if(ThisSum > MaxSum) //求出当前序列的最大子序列和
MaxSum = ThisSum;
}
return MaxSum;
}
__int64 Random(__int64 m,__int64 n) //指定范围内随机数
{
__int64 pos,dis;
if(m == n) //m=n则表示范围内只有一个数字
{
return m;
}
else if(m > n) //m>n则说明取[m,n]区间内数字
{
pos = n;
dis = m - n + 1;
return rand() % dis + pos;
}
else //m>n则说明取[n,m]区间内数字
{
pos = m;
dis = n - m + 1;
return rand() % dis + pos;
}
}
void MakeRandomSequences(__int64 m,__int64 n,__int64 num) //产生随机序列
{
ofstream filerandom("G:\\sequences.txt");
srand((int)time(NULL)); //根据时间产生相应种子值
for(int i=0 ; i < num; i++)
{
filerandom << Random(m,n) <<" ";
if(!((i + 1) % 10)) //数据量逢十换行
filerandom << endl;
}
filerandom.close();
}
int main()
{
//测试数据
// __int64 a[] = {4,-3,5,-2,-1,2,6,-2};
// __int64 n = 8;
// cout << algorithm1(a,n) << endl;
// cout << algorithm2(a,n) << endl;
// cout << algorithm3(a,n) << endl;
// cout << algorithm4(a,n) << endl;
// MakeRandomSequences(-1000,1000,100000); //产生随机序列
__int64 a[200000];
__int64 n = 0;
ifstream filesequ("G:\\sequences.txt");
if(!filesequ.is_open()) //打开失败处理
{
cout<<"Error opening file";
return -1;
}
while(!filesequ.eof())
{
filesequ >> a[n++];
}
filesequ.close();
//PS:测试只需要把调用算法注释去掉
// cout << algorithm1(a,n) << endl;
// cout << algorithm2(a,n) << endl;
// cout << algorithm3(a,n) << endl;
cout << algorithm4(a,n) << endl;
return 0;
}