递归是什么?
在定义一个过程或函数时,出现调用本过程或本函数的成分称为递归
如果一个递归过程或函数中的递归调用语句是最后一条执行语句,则称这种递归调用为尾递归
例如:计算阶乘函数
int f(int n){
if(n==0){
return 1;
} else return (f(n-1)*n);
}
递归解决问题应满足三个条件
- 需要解决的问题可以转化为一个或多个子问题求解,而这些子问题的求解方法与原问题相同,只是数量规模上不同
- 递归调用次数必须是有限
- 必须要结束条件终止递归
递归优点:结构简单、清晰、方便证明准确性
递归缺点:占用内存多,执行效率低、不容易优化
什么时候使用递归?
- 定义是递归的:许多数学公式、定义是递归时。例:阶乘、Fibonacci数列等
- 数据结构是递归的:例:单链表、树等
typedef struct LNode{
ElemType data;
struct LNode *next;
}LinkNode;
//结构体LNode的声明用到了它本身
//利用递归方式求单链表所有data域的和
int sum(LinkNode *L){
if(L==NULL){
return 0;
} else return (L->data+sum(L->next));
}
- 问题的求解方式是递归的:Hanoi问题
汉诺塔问题的规则在此不再赘述
设Hanoi(n,x,y,z)表示将n个盘片从x轴,经由y轴,移动到z轴
我们可以将其拆分为三步进行(找到递归公式)
第一步:将x轴上 n-1 个盘片经由 z轴 移动到 y轴
第二步:将x轴上最后一个盘片直接移动到 z轴
第三步:将y轴上 n-1 个盘片经由 x轴 移动到 z轴
那么问题是:我们如何完成第一步和第三步呢?
其实第一步和第三步又可以分别拆分为上述三个步骤(递归公式)
递归出口:当只有一个盘片时,可以将它直接移动。
代码实现
#include <stdio.h>
//汉诺塔
void hanoi(int n,char A,char B,char C){
if(n==1){
printf("%c -> %c\n",A,C);
} else{
hanoi(n-1,A,C,B);
printf("%c -> %c\n",A,C);
hanoi(n-1,B,A,C);
}
}
int main(){
hanoi(3,'A','B','C');
return 0;
}
emmm,我的语言表达能力更进一步描述清楚
你可以手动执行一次函数,一定要注意形参和实参,通过一个栈模拟,便可以理解了!
这里推荐几个B站up主,我也是看他们的视频才理解的,
首先了解汉诺塔问题可以看李永乐老师
然后看“正月点灯笼”的递归入门视频
最后整个函数的执行步骤可以看“懒猫老师”的视频。
顺便贴一下汉诺塔问题的非递归写法
总结:在面对递归问题时,找到递归公式,递归出口是关键