# 递归
栈的思想:是先进后出!!
C语言运行时堆栈支持递归函数的实现。递归函数就是直接或者间接调用自身的函数。在许多教科书把计算阶乘和,斐波拉数列用来当作递归的例子
我决定这个非常不好。在阶乘的例子中,没有啥优越性,在斐波那契的例子,它的效率非常之低。
在这个地方,我们举一个比较简单的例子,我拿来说明递归。程序的目的是把一个整数从二进制形式转换为可以打印的字符形式!!
(把整数转换为可以输出的字符! 输入 4267 ,我们需要依次产生字符‘4’ ‘2’ ‘6’ ‘7’)。
我们采用规定策略是把这个值反复除以10,并打印各个数。例如:4267%10 的余数是7 ,但是我不能直接打印这个余数。我们需要打印的这个数是字符‘7’
在ASCII码中,字符‘7’的值是55,所以我们需要在余数上加上48来获取正确的字符。
while(a)
{
printf("%c",(a%10)+'0');
a /= 10;
//两句话就完成了,只是说获取的答案是反的,我需要4267 , 你打印的是 7624
}
我们把这个函数转换成递归来修正这个问题!!
#include <stdio.h>
void int_char_ascii(int value)
{
int num = 0;
num = value/10;
if(num != 0)
{
//int_char_ascii(num);
func
}
printf("%c",value % 10 + '0');
}
int main()
{
int_char_ascii(4267);
return 1;
}
递归是如何帮助我们以正确的顺序打印这些字符????下面就是这个函数的工作流程
1、将参数值除以10
2、如果num的值为非0,调用int_char_ascii()打印当前值的各个数字
3、接着,打印步骤1中出发运算的余数
一旦你理解了递归,阅读递归函数的最简单的方法不是去纠结它的执行过程,而是相信递归函数会顺利完成它的任务。
如果你的每一个步骤都正确无误的化, 同时你的限制条件也设置正确,并且每次调用之和更加的接近限制条件就ok了,
这样子我们的递归函数才能顺利完成它的任务。
## 追踪递归函数
为了能理解递归函数的工作原理,你需要追踪递归调用的执行过程,所以让我们来进行这项工作。
追踪一个递归函数执行过程的关键,就是你要理解函数中所声明的变量是如何存储的。
当函数被调用的时候,它的变量的空间是常见于运行时堆栈上。
以前调用的函数的变量仍保留栈堆上的,但是他们会被新的函数的变量所覆盖,因此不能被访问。
当递归函数调用自身的时候,情况也是这样子的。每进行一次新的调用,都会创建一批变量,
他们将会”覆盖“函数前一次调用所创建的变量。当我们追踪一个递归函数的执行过程的时候,
必须把分属于不用次调用的变量区分开来,以避免混淆。
见追踪递归函数.png
## 问题引入
我们班有10个同学
我问第10个同学,你几岁了,他说,他比第9个同学大两岁
我问第9个同学,你几岁了,他说,他比第8个同学大两岁
......
我问第1个同学,你几岁了,他说,他10岁
请问,第n个同学几岁了!
写一个函数来完成这个任务
1、确定任务目标
求第n个同学年龄
age
2、确定完成任务的输入参数
age(int n)
3、确定任务完成后,返回值(返回当前第n个学生的年龄)
int age(int n )
{
}
4、具体的算法实现
a、你要确定结束条件是什么?
int age(int n )
{
if(n == 1)
{
return 10;
}
else
{
return age(n-1)+2; //从第n-1个同学的年龄+2
}
}
int main()
{
printf("%d\n",age(10));
}
### 递归的说法:
直接或者间接调用函数的本身,这个过程称之为”递归”,自己调用自己
## 在什么情况下使用递归??
是不是所有的问题都可以使用递归??显然不是
在解决一个问题的时候,解决思路 化成(分解)与问题本身类似或者相同的问题的时候,就可以考虑递归。
在上面这个例子中:求第n个学生的年龄的 <------------->求第n-1个同学问题+2 <----------->求第n-2个同学的年龄+2..............
在解决一个问题的过程中,需要解决与这个问题类似的问题,才会去采用递归
是不是所有的递归函数,C语言都支持?? 肯定不是,原因是:不能无限递归下去
C语言能解决的递归问题,需要满足两个条件:
1、问题的本身是就是一个递归------》递归函数式
2、递归不能无限递归
适合那些递归到一定程度时,答案就显而易见的,一定要有退出递归的条件,不能无限递归
什么时候使用递归??
在你解决思路过程中,发现“递归问题”,并且自己可以写出这个递归函数式的时候!!
解决问题时:
要把一个大问题,分解成多个小问题或者多个步骤
如果这些小问题 或者 多个步骤 中有一个是和原问题类似的,这种情况下就使用递归
进一步展开,“用自然语言来描述这个意思”
“再使用形式化语言来描述这个思路” ---- 递归函数式
代码
第一步:按照函数的步骤来写函数
第二部:要确定递归的结束条件
第三步:递归函数式
#include<stdio.h>
/*汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower)。
有三根柱子,在一根柱子上从下往上按照大小顺序摞着n片圆盘。
要把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。
并且规定,任何时候,在小圆盘上都不能放大圆盘,
且在三根柱子之间一次只能移动一个圆盘。
问应该如何操作?
*/
int i=0;
int move(int n,char x,char y)
{
i++;
printf("第%d步把%d个圆盘从%c移动到%c\n",i,n,x,y);
}
int hannuo(int n,char a,char c,char b)
{
if(n==1)
{
move(n,a,c);
}
else
{
hannuo(n-1,a,c,b);
move(n,a,c);
hannuo(n-1,b,a,c);
}
}
int main()
{
int n;
printf("请输入一个数n:\n");
scanf("%d",&n);
hannuo(n,'A','C','B');
}