这个算法编程珠玑中给出了详细的描述,但书中的代码比较简单,其中并没有给出如何获取子串的起始位置的计算。这里给出完整的C语言实现,代码全部在CodeBlocks下测试通过。
1.平方和算法
/* 求连续的一串数中具有最大和的子串,O(n*n)*/
int array_max_subarray_calc(int *array,int num,int *from,int *to)
{
int i,j;
int max = 0;
int *sum_array = malloc(4*num);
for(i = 0;i < num;i++)
{
sum_array[i] = 0;
*from = i;
for(j = i;j < num;j++)
{
sum_array[i] += array[j];
if(sum_array[i] > max)
{
max = sum_array[i];
*to = j;
printf("max updated to %d,[%d,%d]\n",max,i,j);
}
}
}
return max;
}
2 分而治之算法
/* 求连续的一串数中具有最大和的子串, D&C
[l,m],[m+1,u]
*/
int array_max_subarray_calc_DC(int *array,int l,int u,int *from,int *to)
{
int max_l,max_m,max_u;
int sum,max;
int m = (l+u)/2;
int i;
int from_l,to_l,from_m,to_m,from_u,to_u;
if(l > u)
return 0;
if(u == l)
{
*from = u;
*to = u;
return array[u];
}
max_l = sum = array[m];from_m = m;
for(i = m-1;i >=l;i--)
{
sum += array[i];
if(sum > max_l)
{max_l = sum;from_m = i;}
}
max_u = sum = array[m+1];to_m = m+1;
for(i = m+2;i<=u;i++)
{
sum += array[i];
if(sum > max_u)
{max_u = sum;to_m = i;}
}
max_m = max_l + max_u;
max_l = array_max_subarray_calc_DC(array,l,m,&from_l,&to_l);
max_u = array_max_subarray_calc_DC(array,m+1,u,&from_u,&to_u);
max = MAX(max_m,max_l);
max = MAX(max,max_u);
if(max == max_m)
{*from = from_m;*to = to_m;}
else if(max == max_l)
{*from = from_l;*to = to_l;}
else
{*from = from_u;*to = to_u;}
printf("[%d,%d,%d],max_m=%d,max_l=%d,max_u=%d\n",l,m,u,max_m,max_l,max_u);
printf("from=%d,to=%d\n",*from,*to);
printf("------------------------------------------\n");
return max;
}
3 一次扫描算法
/* 求连续的一串数中具有最大和的子串, 一次扫描
max = MAX(maxsofar,maxend])*/
int array_max_subarray_On(int *array,int n,int *from,int *to)
{
int max_sofar,max_end;
int i;
int from_end = -1,to_end = -1;
max_sofar = max_end = 0;
*from = *to = -1;
for(i = 0;i < n;i++)
{
max_end = max_end + array[i];
max_end = MAX(max_end,0);
if(max_end > 0)
{
if(from_end == -1)
from_end = i;
to_end = i;
}
else
from_end = to_end = -1;
max_sofar = MAX(max_sofar,max_end);
if(max_sofar == max_end)
{
*from = from_end;
*to = to_end;
}
}
printf("max sub array=%d,from=%d,to=%d\n",max_sofar,*from,*to);
return max_sofar;
}