递归入门
1.递归概论及最简单递归实现
a.递归能解决什么问题
- 递归能够解决循环的所有问题,但是,循环不一定能解决递归的问题。
b.递归解释
首先声明,我对递推的看法完全是像数列中的递推公式的一个东西,而不是正统的先逆后顺的思想。如有不完善之处还请各位指正。
递归就像是一个数列的递推公式: f ( x ) = k ∗ f ( x − 1 ) + b f(x)=k*f(x-1)+b f(x)=k∗f(x−1)+b(不过我没有考证过是不是这个原因才叫递归)
所以从这里可以看出,基本上循环的内容,你写个递归的函数都能做出来。
c.代码实现
i.构成:
从数列的启发中,你可以很容易看到,所有的递归式子必须要有一个首项和递推关系。
在递归里面也有这样的概念,不过我们把首项叫做出口,把递推关系叫做关系。
出口:就是使变量停止变化的位置。不过请注意我对出口的解释中,有一层数字从大到小的含义。换句话说,就是数列中的首项一般是从小到大进行计算,而递归里面的数字是从大到小依次排列。在最小点实现循环的停止。(这段文字有点长,不想看也罢,反正一会儿会上代码)
关系:当然就是递推关系了。
从数学到代码(划重点):
数学公式中的 f ( x ) = k ∗ f ( x − 1 ) + b f(x)=k*f(x-1)+b f(x)=k∗f(x−1)+b等价于代码中的
return k*f(n-1)+b;
ii.举例分析:
斐波那契数列的实现
按照数学方法,应该写成首项: f ( 1 ) = a , f ( 2 ) = b f(1)=a,f(2)=b f(1)=a,f(2)=b。递推关系: f ( x ) = f ( x − 1 ) + f ( x − 2 ) f(x)=f(x-1)+f(x-2) f(x)=f(x−1)+f(x−2)。这样就能得出第N项的值了。
按照C语言,应该写成
int f(int n) { if(n==1) //理解下“出口”的含义(这个里面不能打高亮) return 1; else if(n==2) //出口2 return 1; else //实现递推 return f(n-1)+f(n-2); }
- 通过这个好好理解下递推中的逆推思想。
iii.疑难解答(此部分为个人思考,如有错误还请指正):
- 有的
好奇宝宝会问:为什么不正着推而反着推?- 在我看来,正着推的话,要多加一个变量,而反着推,则会省略这一步冗杂项。
- PS:此疑难解答仅限于此文我的递推思想,如果是正统 先逆后顺的思想的话,请自动忽略此部分。
iv.附录:
斐波那契数列的实现:
#include <stdio.h>
int f(int n) //斐波那契数列的递推表示
{
if(n==1)
{
return 1;
}
else if(n==2)
{
return 1;
}
else
return f(n-1)+f(n-2);
}
int main()
{
int n;
scanf("%d",&n); //输入你想要求的轮数(兔子生几轮)
printf("%d",f(n));
return 0;
}
友情提示,冒泡法也可以用递归式子写出
- 仔细思考,随后给出答案。
2.递归与数组
a.基础奠基:
- 数组指针是指向数组首元素的地址的指针,其本质为指针(这个指针存放的是数组首地址的地址,相当于2级指针,这个指针不可移动)。
b.代码实现
求一个数组中前N项和
int sum(int arr[],int n)
{
if(n==0)
return arr[0];
else
return sum(arr,n-1)+arr[n];
}
实际上,就是将基础奠基里面的内容加入进去就行了,因此我就不再写注释了。
3.总结及习题练习:
a.总结:
- 在这个里面,第一步要做的是确定关系,就是把最后一项和前面几项分成两部分。例如上个代码,就是将前几项sum(arr,n-1)和最后一项arr[n]分离出来,进行关系处理(比如比较大小,求和等)。
return sum(arr,n-1)+arr[n];
- 那么,第二步要做的是确定出口,确定出口条件和输出结果 。例如上个代码,就是将第一项的结果列了出来。
if(n==0)
return arr[0];
- 因此,你要明白:递归就是找到出口和关系,再利用你高中打下的数学基础,把递归解释或写清楚!
b.习题练习:
i.比较一个数组内元素的大小
代码分析:
出口:就是输出条件(if)和输出结果(return)。
if(n==0)
return a[0];
- 关系:把最后一项(a[n])和除最后一项外的所有项(max(a,n-1))进行关系处理(比大小)
- PS:从下面的代码也可看出,关系处理也是输出条件和输出结果的复合体。
if(max(arr,n-1)>arr[n])
return max(arr,n-1);
else
return a[n];
最重要的:
没事别用递归!!!
注释:在看上面链接的时候,摁住ctrl点击超链接就行。
————————————————————————————————————————
高山仰止,景行行止,虽不能至,然心向往之。
——《诗经·小雅》