您的位置:首页 > 其它

求整数数组中和最大的子数组的3种方法

2013-03-09 21:16 302 查看
输入一个整型数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。要求时间复杂度为O(n)。

使用三种方式实现,分别是蛮力法:bf_MaxSubArray,分治法:dc_MaxArray,和O(n)实现的单循环法find_max。

#include"stdio.h"
#include"math.h"
#include"time.h"
#include"windows.h"
#define MIN_INT -10000
#define MAX_INT 10000
typedef struct{
int max_left;
int max_right;
int max;
}maxinfo;

maxinfo bf_MaxSubArray(int *a,int n)
{
maxinfo max;
max.max_left= 0;
max.max_right= 0;
max.max= MIN_INT;
int tmp=0;
for(int i=0;i<n;i++)
{
for(int j=i;j<n;j++)
{
tmp += a[j];
if(tmp > max.max)
{
max.max = tmp;
max.max_left = i;
max.max_right = j;
}
}
tmp = 0;
}

return max;
}

maxinfo dc_FindMaxCrossingSubArray(int *a,int left,int mid,int right)
{
maxinfo leftMax;
leftMax.max_left= mid;
leftMax.max_right = mid;
leftMax.max= MIN_INT;
int tmp = 0;
for(int i=mid;i>=left;i--)
{
tmp += a[i];
if(tmp>leftMax.max)
{
leftMax.max = tmp;
leftMax.max_left = i;
}
}

maxinfo rightMax;
rightMax.max_left=mid+1;
rightMax.max_right = mid+1;
rightMax.max= MIN_INT;
tmp = 0;
for(int j = mid+1;j<right+1;j++)
{
tmp += a[j];
if(tmp>rightMax.max)
{
rightMax.max = tmp;
rightMax.max_right = j;
}
}

leftMax.max += rightMax.max;
leftMax.max_right = rightMax.max_right;
return leftMax;

}
maxinfo dc_MaxArray(int *a,int left,int right)
{
if(left==right)
{
maxinfo sgele;
sgele.max_left=left;
sgele.max_right = right;
sgele.max= a[left];
return sgele;
}
else
{
int mid = (int)floor((left+right)/2);
maxinfo tmp;
maxinfo maxleft = dc_MaxArray(a,left,mid);
maxinfo maxright = dc_MaxArray(a,mid+1,right);
maxinfo maxcross = dc_FindMaxCrossingSubArray(a,left,mid,right);
tmp = maxleft.max>maxright.max?maxleft:maxright;
tmp = tmp.max>maxcross.max?tmp:maxcross;
return tmp;
}
}
void show(maxinfo max)
{
printf("收益最大的是:%d号前买入,%d号后卖出,收益$%d/股.\n",max.max_left+1,max.max_right+1,max.max);
}

void find_max(int *ary,int ARYSIZE)
{
int max=0;//保存最大和
int curSum=0;//保存当前和
int curStart=0;//当前和的起始位置
int start=0;//最大和的起始位置
int end=0;//最大和的终止位置
for(int i=0;i<ARYSIZE;i++)
{
if(i==0)
{
curSum=max=ary[i];
continue;
}

if(curSum<0)
{
curSum=0;//与负数相加,和会减小,所以抛弃以前的和
curStart=i;
}
//最大值已经被保存下来,所以请大胆的继续往前加
curSum += ary[i];
//当前和被保存为最大值,记录下它的起始位置和结束位置
if(curSum>max)
{
max=curSum;
start=curStart;
end=i;
}
}

printf("和最大的子数组为:\n");
for(int j=start;j<=end;j++)
{
printf("%d ",ary[j]);
}
printf("= %d",max);
}
void main()
{
int n = 16;
int a[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
//{-13,-3,-25,-20,-3,-16,-23,-18,-20,-7,-12,-5,-22,-15,-4,-7};//
int i=clock();
show(bf_MaxSubArray(a,n));
printf("\n==============\n");

find_max(a,n);
printf("\n==============\n");
printf("计算耗时:%dms\n",clock()-i);

int mid = (int)floor((n-1)/2);
show(dc_FindMaxCrossingSubArray(a,0,mid,n-1));

maxinfo result;
LARGE_INTEGER nFreq;

LARGE_INTEGER nBeginTime;

LARGE_INTEGER nEndTime;

double time;

QueryPerformanceFrequency(&nFreq);

QueryPerformanceCounter(&nBeginTime);
//开始
result = bf_MaxSubArray(a,n);//dc_MaxArray(a,0,n-1);

QueryPerformanceCounter(&nEndTime);

time=(double)(nEndTime.QuadPart-nBeginTime.QuadPart)/(double)nFreq.QuadPart;

printf("%f微妙\n",time);
show(result);
printf("\n");

}


其中最优方法的参考地址:求整数数组中和最大的子数组
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐