C Algorithm.Max_length
Mark Allen Weiss的data structures and algorithm analysis in c
求一个整数序列的最大的连续子列和:
1 #include <stdio.h> 2 3 static int Max3( int A, int B, int C ) 4 { 5 return A > B ? ( A > C ? A : C ) : ( B > C ? B : C ); 6 } 7 8 static int maxsubsum(const int a[], int left, int right) 9 { 10 int maxleftsum, maxrightsum; 11 int maxleftbordersum, maxrightbordersum; 12 int leftbordersum, rightbordersum; 13 int center, i; 14 15 if(left == right) 16 if(a[left] > 0) 17 return a[left]; 18 else 19 return 0; 20 21 center = ( left + right ) / 2; 22 maxleftsum = maxsubsum(a, left, center); 23 maxrightsum = maxsubsum(a, center + 1, right); 24 25 maxleftbordersum = 0; leftbordersum = 0; 26 27 for( i = center; i >= left; i--) 28 { 29 leftbordersum += a[i]; 30 if(leftbordersum > maxleftbordersum) 31 maxleftbordersum = leftbordersum; 32 } 33 34 maxrightbordersum = 0; rightbordersum = 0; 35 for(i= center + 1; i<= right; i++) 36 { 37 rightbordersum += a[i]; 38 if( rightbordersum > maxrightbordersum) 39 maxrightbordersum = rightbordersum; 40 } 41 42 return Max3(maxleftsum, maxrightsum, maxleftbordersum + maxrightbordersum); 43 } 44 45 maxsubsesquencesum( const int a[], int n) 46 { 47 return maxsubsum( a, 0, n-1); 48 } 49 50 int main() 51 { 52 static int A[ ] = { 4, -3, 5, -2, -1, 2, 6, -2 }; 53 static int B[ ] = { -3, -2 }; 54 printf( "Maxsum = %d\n", maxsubsesquencesum( B, sizeof( B ) / sizeof( B[ 0 ] ) ) ); 55 return 0; 56 }
上面的代码的解释:
把一个序列从中间分成两个子序列,然后对这两个子序列分别求最大子列的和 S1和S2,还有,求出包含中间分界元素的最大子列的和S3, 三者中的最大者就是要求的这整个序列的最大子列的和,Max3(S1, S2,S3)。
这个方法用到了递归方法,即,当所求序列的元素很多时,把他分解成两个更小的子列,当子列分解到只剩下1个元素时,就可以向上返回最大子列的和。
Weiss对基础情况的处理中,有点粗糙了,即上述代码第15~19行中,
15 if(left == right) 16 if(a[left] > 0) 17 return a[left]; 18 else 19 return 0;
为什么当 a[left] <= 0 的时候就要返回0呢,如果整个序列都是负数呢? 那就应该返回此序列中的最大负数就可以了,因为 负数+负数 会越加越小。
Weiss又给出了一个更简洁的算法:
1 int maxsubsum(int a[], int n) 2 { 3 int thisSum=maxSum=0,j; 4 5 for(j=0; j < n; j++) 6 { 7 if(thisSum > maxSum) 8 maxSum=thisSum; 9 else if(thisSum < 0) 10 thisSum = 0; 11 } 12 13 return maxSum; 14 }
这个算法的思路是,顺次扫描序列的元素并求其和,如果当前和大于先前保存的最大和,则置最大和为当前和。
如果当前和小于0,则置当前和为0。
这个算法同样假设最大和为负数时,返回0。
根据 http://blog.csdn.net/v_JULY_v/article/details/6444021 第一节第3个算法,加上我的一个改进,可以给出序列元素全是负数的情况下的解:
1 static int maxsubsum(int a[], int n) 2 { 3 int thisSum, maxSum, maxelem, j; 4 thisSum=0; 5 maxSum=maxelem=a[0]; 6 for(j=0; j < n; j++) 7 { 8 if(thisSum>=0) //如果加上某个元素,sum>=0的话,就加 9 thisSum+=a[j]; 10 else 11 thisSum=a[j]; //如果加上某个元素,sum<0了,就不加 12 13 if( maxelem < a[j]) 14 maxelem = a[j]; 15 16 if(thisSum > maxSum) 17 maxSum=thisSum; 18 19 if(maxelem > maxSum) 20 maxSum=maxelem; 21 } 22 23 return maxSum; 24 } 25 26 int main() 27 { 28 static int a[] = { 4, -3, 5, -2, -1, 2, 6, -2 }; 29 static int b[] = { -4, -3, -5, -2, -1, -2, -6, -2 }; 30 static int c[] = { 4, -3, 5, -2, 0, -1, 2, 16, -2 }; 31 32 printf( "Maxsum of a = %d\n", maxsubsum( a, sizeof( a ) / sizeof( a[ 0 ] ) ) ); 33 printf( "Maxsum of b = %d\n", maxsubsum( b, sizeof( b ) / sizeof( b[ 0 ] ) ) ); 34 printf( "Maxsum of c = %d\n", maxsubsum( c, sizeof( c ) / sizeof( c[ 0 ] ) ) ); 35 return 0; 36 }