标签:style class blog code java http
问题:采用递归方法计算给定整型数组元素之和。
以下给出几种递归算法的实现:
1 int sum1(int a[], int n) 2 { 3 if(n > 0) 4 return a[n-1] + sum1(a, n-1); 5 else 6 return 0; 7 } 8 9 int sum2(int a[], int n) 10 { 11 if(n > 0) 12 return a[n-1] + sum2(a, --n); 13 else 14 return 0; 15 } 16 17 int sum3(int a[], int n) 18 { 19 if(n > 0) 20 return a[--n] + sum3(a, n-1); 21 else 22 return 0; 23 } 24 25 int sum4(int a[], int n) 26 { 27 if(n > 0) 28 return a[n] + sum4(a, --n); 29 else 30 return 0; 31 } 32 33 int sum5(int a[], int n) 34 { 35 if(n > 0) 36 return a[--n] + sum5(a, n); 37 else 38 return 0; 39 } 40 41 int sum6(int a[], int n) 42 { 43 while(n > 0) 44 return a[n-1] + sum6(a, n-1); 45 46 return 0; 47 }
为验证和比较上述几种算法实现,编写测试代码如下:
1 int main(void) 2 { 3 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 4 printf("sum1 = %d\n", sum1(a, 10)); 5 printf("sum2 = %d\n", sum2(a, 10)); 6 printf("sum3 = %d\n", sum3(a, 10)); 7 printf("sum4 = %d\n", sum4(a, 10)); 8 printf("sum5 = %d\n", sum5(a, 10)); 9 printf("sum6 = %d\n", sum6(a, 10)); 10 return 0; 11 }
在GCC3.2.3编译器下执行结果为:
1 sum1 = 55 2 sum2 = 55 3 sum3 = 30 4 sum4 = -1076625666(随机值) 5 sum5 = 55 6 sum6 = 55
而在VC6.0编译器下执行结果为:
1 sum1 = 55 2 sum2 = -858993415(固定值) 3 sum3 = 30 4 sum4 = 55 5 sum5 = 55 6 sum6 = 55
可见:
1. 对于a[n-1] + sum2(a, --n),GCC编译器先加法后将n自减,等效于a[n-1] + sum2(a, n-1);而VC编译器先将n自减,等效于a[n-2] + sum2(a, n-1);
2. 对于a[--n] + sum3(a, n-1),GCC编译器先将n自减,等效于a[n-1] + sum2(a, n-2);而VC编译器与之相同;
3. 不同的编译器对表达式和自减(或自增)运算符的处理顺序不同。因此,编程时算式中应采用直白易懂的写法(如sum1),避免使用自增/自减;
4. 递归算法中,sum1中的if与sum6中的while等效。
5. 遇到语法正确但运行诡异的问题时,不妨怀疑编译器是否存在bug。
最后,简要提及两种编译器下sum4和sum2执行后的异常值。分析函数调用过程可知,两个异常值均由数组越界导致(gcc-sum4的a[10],vc-sum2的a[-1])。-1076625666的16进制表示形式为0xbfd3fefe,很明显是个Linux栈区地址;而-858993415的16进制表示形式为0xccccccf9,0xcc是VC编译器Debug模式下系统为未初始化的栈区变量所赋的初值。此外,因栈区地址为运行时概念,故每次执行后sum4结果可能略有变化;而VC的0xcc特殊占位符取值固定,故sum2结果不随执行次数而变。
将测试代码稍加改造:
1 int main(void) 2 { 3 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 4 int n = sizeof(a) / sizeof(a[0]); 5 printf("sum1 = %d\n", sum1(a, n)); 6 printf("sum2 = %d\n", sum2(a, n)); 7 printf("sum3 = %d\n", sum3(a, n)); 8 printf("sum4 = %d\n", sum4(a, n)); 9 printf("sum5 = %d\n", sum5(a, n)); 10 printf("sum6 = %d\n", sum6(a, n)); 11 return 0; 12 }
则GCC编译器会给出不同的结果:
1 sum1 = 55 2 sum2 = 55 3 sum3 = 30 4 sum4 = 64 5 sum5 = 55 6 sum6 = 55
因时间有限,本文仅就表面现象说明,未进行深入分析。读者若有兴趣可自行分析下背后的机理,分析手段参考如下文章:
标签:style class blog code java http
原文地址:http://www.cnblogs.com/clover-toeic/p/3782438.html