一个函数在他的函数体内调用它自身称为递归调用,这种函数称为递归函数。执行递归函数将反复调用自身(也就是相当于嵌套函数),每一次的调用就进入新的一层函数,执行到最后结束的那一行代码就开始从里面一层一层的退出函数
#include <stdio.h> //求n的阶层 int factorial(int n) { if (n<2) { return 1; //最里层的结束语句 }else{ return factorial(n-1)*n;//return是最后退出的时候执行,如果没有退出递归是不会执行return的 } }
递归的进入
(1)求5!,即调用factorial(5).当进入factorial()函数体后,由于形参n的值为5,不等于0或1,所以执行factorial(n-1)*n,也就是执行了factorial(4)*5.为了求得这个表达式的结果,就必须先调用factorial(4),并暂停其他操作,换句话说,在得到factorial(4)de 结果前,不能进行其他操作,以此类推一直到n==1,结束。
逐层进入递归过层 层次/层数 实参/形参 调用形式 需要计算的表达式 需要等待的结果 1 n=5 factorial(5) factorial(4)*5 factorial(4)的结果 2 n=4 factorial(4) factorial(3)*4 factorial(3)的结果 3 n=3 factorial(3) factorial(2)*3 factorial(2)的结果 4 n=2 factorial(2) factorial(1)*2 factorial(1)的结果 5 n=1 factorial(1) 1 无
递归的退出
当递归进入到最内层的时候,递归就结束了,就开始逐层退出了,也就是逐层执行return语句。
(1)n的值为1的时候达到最内层,此时return 出去的结果为1,也就是factorial(1)的调用结果为1.
(2)有了factorial(1)的结果,就可以返回上一层的计算factorial(1)*2的值,此时得到的值为2,return 出去的结果也为2,也即factorial(2)的调用结果为2.
层次/层数 | 实参/形参 | 调用形式 | 从内层递归得到的结果 (内层函数的返回值) | 表达式的值 (当次调用的结果) |
5 | factorial(1) | 1 | 无 | |
4 | factorial(2) | factorial(1)*2 | factorial(1)的返回值,也就是1 | 1*2 = 2 |
3 | factorial(3) | factorial(2)*3 | factorial(2)的返回值,也就是2 | 2*3 = 6 |
2 | factorial(4) | factorial(3)*4 | factorial(3)的返回值,也就是6 | 6 * 4 = 24 |
1 | factorial(5) | factorial(4)*5 | factorial(4)的返回值,也就是24 | 24 * 5 = 120 |
递归的条件
每一次递归函数都应该只进行有限次的递归调用,否则它就会进入死胡同,永远也不会退出,将会没有任何意义
------------------------------------------- 分割线 --------------------------------------------------
中间递归函数
所谓中间递归就是发生递归的函数在函数的中间,而不是末尾
字符串反转(逆置)
#include <stdio.h> #include <stdlib.h> char *reverse(char *char){ int len = strlen(str); if (len > 1) { char ctemp = str[0];//临时变量存每一次递归的第一个元素 str[0] = str[len-1]; str[len-1] = '\0'; reverse(str + 1);//递归调用 str[len-1] = ctemp;//每一次递归函数返回之后,最后一个元素都等于每一次递归的第一个元素 } return str; } int main(){ char str[20] = "hello world"; printf("%s\n",reverse(str)); return 0; }
递归的过程
第十一行代码,调用reverse()的实参为 str+1,这个会导致形参的str的指向改,每次递归调用str都会向后移动一个字符位置
reverse() 的整体思路是,每次调用函数只交换字符串开头和末尾的两个字符串,其他字符一律不管,并且这个交换过程也是分两个阶段完成的
1,在逐层进入递归阶段,reverse()只是把字符串最后的一个字符移动到最前面,但是并没有把最前面的字符串移动到最后边,而是把最前边的字符保存到ctemp变量
2,在逐层退出递归的阶段,reverse()才把ctemp变量保存的字符放到字符串最后
在一个字符串中"\0"就是一个字符串的结束