前几天到复旦大学参加了DENA的宣讲会,有一道循环递归的题要求写出运行结果,当时还感觉挺简单 没想到回去把代码编译运行一遍,发现错了···,唉,感觉自己在算法方面还是太弱了点,故写这篇博客分析一下,当做自己的学习笔记吧,如果有错希望大家指出来,谢谢。
题目的代码如下:
void sub(int a[], int n)
{
if(n > 1)
{
for(int i = 0; i < n - 1; i ++)
{
a[i] = a[i] + a[i + 1];
sub(a, n - 1);
}
}
}
int main()
{
int a[] = {0, 1, 2, 3};
sub(a, 4);
}
求运行结束后第二个元素的值为多少
这个题目的难点主要是在递归的基础上又增加了循环,很容易被绕晕,所以分析起来可能难一点···
分析这个函数的运行过程:
1、判断n是否大于1,如果n > 1执行第2步,否则返回(对于递归来说就是返回上一层函数中了)
2、int i从 0 到 n - 2循环做以下两步
a、a[i] = a[i] + a[i + 1];
b、将n 减1,再次调用这个函数
分析过程:
1、对于 sub(a, 4) ,循环3次,从i = 0 到 i =2,调用3次sub(a,3);
2、对于 sub(a, 3) ,循环2次,从i = 0 到 i =1,调用2次sub(a,2);
3、对于 sub(a, 2) ,循环1次,从i = 0 到 i =0,调用1次sub(a,1);
4、对于 sub(a, 1) ,循环0次,什么也不干,返回上一层。
也许画个图会更容易理解一点:
(注:第三行和第四行的每一步都有a[i] = a[i] + a[i + 1]; 因为图太小不好全部写上去)
有了图就更容易分析程序是怎么运行的了。
对于int a[] = {0, 1, 2, 3};
当调用 sub(a, 4)时,进入第图上的1步,根据上面归纳的函数运行过程:
1、进入 i 从 0 到 2的循环,从 0 开始,执行a[i] = a[i] + a[i + 1,即a[0] = a[0] + a[1] ];此时数组变为{1,1,2,3};
然后调用sub(a,3),此时进入一下层递归。
2、进入sub(a, 3)这一层,就是图中标示的第2步,
同理,进入i 从 0 到 1的循环,从 0 开始,执行a[i] = a[i] + a[i + 1,即a[0] = a[0] + a[1] ];此时数组变为{2,1,2,3};
然后调用sub(a,2),此时进入一下层递归。
3、进入sub(a, 2)这一层,就是图中标示的第3步,
同理,进入i 从 0 到 0的循环,从 0 开始,执行a[i] = a[i] + a[i + 1,即a[0] = a[0] + a[1] ];此时数组变为{3,1,2,3};
然后调用sub(a,1),此时进入一下层递归。
4、进入sub(a,1)这一层,因为该递归函数的边界条件为n > 1,调用sub(a, 1)已经达到了边界条件,什么都不会做,返回上一层。
5、上一层递归函数为sub(a, 2),sub(a,2)的循环次数只有1次(for int i = 0; i < n - 1; i ++),从0 到 0,已经执行完毕,继续返回上一层;
6、上一层递归函数为sub(a, 3),sub(a,2)的循环次数有2次,所以执行图中第4步,执行a[i] = a[i] + a[i + 1,即a[1] = a[1] + a[2] ];此时数组变为{3,3,2,3};
然后调用sub(a, 2),此时进入一下层递归。
7、重复3、4、5步骤(重复第三步骤时数组变为{6,3,2,3}),此时返回到sub(a, 3); sub ( a, 3)的循环次数也执行完毕了,继续返回上一层。
8、上一层递归函数为sub(a, 4);此时i=1,进入图中的第6步,执行a[i] = a[i] + a[i + 1,即a[1] = a[1] + a[2] ];此时数组变为{6,5,2,3};
然后调用sub(a, 2),此时进入一下层递归。
9、后面的步骤基本上就是重复之前的步骤了,很容易分析得出数组的变化情况如下:
{1,1,2,3}
{2,1,2,3}
{3,1,2,3}
{3,3,2,3}
{6,2,2,3}
{6,5,2,3}
{11,5,2,3}
{16,5,2,3}
{16,7,2,3}
{23,7,2,3}
{23,7,5,3}
{30,7,5,3}
{37,7,5,3}
{37,12,5,3}
{49,12,5,3}
所以执行完毕后第二个元素变为12.。