函数自己调用自己,这种调用的过程就叫递归。
递归的基本原理:
- 每级函数调用都有自己的变量
- 每次函数调用都会返回一次
- 递归函数中位于递归调用之前的语句,按照被调函数的顺序执行
- 递归函数中位于递归调用之后的语句,按照被调函数相反的顺序执行
- 递归函数必须包含能让递归停止调用的语句。通常,用if语句或其他等价语句在函数形参等于某特定值时终止递归;因此每次递归调用的形参都要使用不同的值。
下面举一个例子,来帮助大家理解以上五个基本原理。
#include<stdio.h>
void recursion(int n)//递归函数
{
printf("这里第%d级递归\n", n);//递归调用之前的语句
if (n < 4)//递归的终止条件
{
recursion(n + 1);
}
printf("打印的数字:%d;那么这就是第%d级递归的递归函数的形参。\n",n,n );//递归调用之后的语句
}
int main()
{
recursion(1);//第一级调用
return 0;
}
输出结果如下:
这里第1级递归
这里第2级递归
这里第3级递归
这里第4级递归
打印的数字:4;那么这就是第4级递归的递归函数的形参。
打印的数字:3;那么这就是第3级递归的递归函数的形参。
打印的数字:2;那么这就是第2级递归的递归函数的形参。
打印的数字:1;那么这就是第1级递归的递归函数的形参。
说明:
这个递归可以看作是:recursion (1) 调用recursion (2) , recursion (2) 调用recursion (3),recursion (3) 调用recursion (4)
因此被调函数的次序应为:recursion (1),recursion (2),recursion (3),recursion (4) 。
从输出结果可以清楚的看到:位于递归调用之前的这条语句
printf("这里第%d级递归\n", n);
正是按照被调函数的次序执行的
这里第1级递归
这里第2级递归
这里第3级递归
这里第4级递归
然而,位于递归调用后的这条语句
printf("打印的数字:%d;那么这就是第%d级递归的递归函数的形参。\n",n,n );
正如第4点原理所说的,是按照与被调函数相反的次序执行的
打印的数字:4;那么这就是第4级递归的递归函数的形参。
打印的数字:3;那么这就是第3级递归的递归函数的形参。
打印的数字:2;那么这就是第2级递归的递归函数的形参。
打印的数字:1;那么这就是第1级递归的递归函数的形参。
过程:
当recursion(4) 结束时,控制返回recursion(3) , 被调函数recursion(4) 把控制返回在调用的那个位置,因此,recursion(3)继续执行后面的代码。
然后当recursion(3)调用结束时,recursion(3)又把控制返回给recursion(2) , 继续执行其后的代码。
recurisn(2)以此类推。
尾递归tail recursion
尾递归就是把递归置于函数的末尾,并且这种递归是最简单的递归形式,因为它相当于循环。
递归与倒序计算
递归在处理倒序时非常方便。比如我们写一个打印整数的二进制数的程序。
#include<stdio.h>
void binary(long n)
{
int r;
r= n % 2;//得到最后一位二进制
if (n >= 2)//如果n还大于等于2,说明还是二进制位;二进制只有0和1
{
binary(n / 2);//n/2相当于把二进制往前移一位
}
putchar(r == 0 ? '0' : '1'); //二进制偶数的末尾是0,集数的末尾是1
}
int main()
{
unsigned long num;
printf("请输出一个十进制数字。\n");
scanf_s("%lu", &num);
printf("它的二进制为:\n");
binary(num);
return 0;
}
打印结果如下
请输出一个十进制数字。
5
它的二进制为:
101
事实上
r=n%2;
这条语句计算的是,最后一位二进制位,这提示我们应该将这条语句写在递归调用之前
而把打印语句
putchar(r == 0 ? '0' : '1');
写在递归调用之后。
这样的话,计算的第一个值(最后一个二进制数)正好是最后一个打印。
- 咱就是说,妙啊!