一、概念
什么函数递归??
函数递归:其实就是程序调用自身的变成技巧。其作用在于可以把一个大型复杂的问题转化为一个与原问题相似1的规模较小的问题来求解
递归的两个必要条件:
存在某个限制条件,当条件满足时,递归不再继续
每次递归调用都向这个限制条件接近
二、程序例子
知道了什么是递归,那就让我们看几个例子来看看递归在程序中的表现吧!
1)实现分别打印一个数的每一位
#include<stdio.h>
//分别打印数字每一位
void print(int n)//1234
{
if(n>9)
{
print(n/10);
}
printf("%d ",n%10);
}
int main()
{
unsigned int num =1234;
print(num);
return 0;
}
怎么理解在函数内部是怎样的一个过程?
为了辅助理解,我们把递归这两个字拆解为递和归
图中红色为递的过程,在主函数中调用print(),然后再根据限制条件进入下一层的调用,一层一层地调用print()函数直到n不满足限制条件为止,在最后一层就会出if语句,进入到print()的末尾,执行操作。
图中蓝色线为归的过程,当我最后一层的print()被调用完后就会回到上一层print()的位置,此时这个print()已经执行完,同样出if语句执行该层print()的最后的操作。一层一层的往上归,直到回到主函数调用print()的位置,然后就执行主函数中的下一步操作。
这样的话,一个简单的递归流程就走完了!!
2)使一个字符串逆序
//反转字符串
#include<stdio.h>
#include<string.h>
void reverse_string(char* arr)
{
int len = strlen(arr);
char temp = *arr;
*arr = *(arr+len-1);
*(arr+len-1) = '\0';
if((strlen(arr+1))>=2)
{
reverse_string(arr+1);
}
*(arr+len-1) = temp;
}
int main()
{
char str[]= "abcdefg";
reverse_string(str);
printf("%s",str);
return 0;
}
设中间变量temp,思想为,先把a放到temp中,再把g下的值给储存a的地址,把g位置的值设为’\0’
在第二层调用函数下,重复类似的操作,不过此时是arr+1,即指针指向了b位置,对"bcdef"执行类似的操作。之后各层都会执行类似的操作,直到不满足限制条件开始回归。
这是最后一层的样子,此时指针指向d位置,而此时该字符串已经不满足限制条件开始回归。而回归操作就是一层一层地将各层函数的临时变量中存储的值赋到相应位置下,直到填充完成,回到主函数。
三、经典问题
经过上述两个例子相信大家对,递归已经有了一个初步的认识。接下来我们来看看一个经典的问题------------汉诺塔
汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
那么我们该如何使用递归来实现这个过程呢??
1)画图理解
这是三层汉诺塔的示意图
这是四层汉诺塔的示意图
我们不难发现,不论是三层还是四层的汉诺塔都会有这样的一个过程;即除了最底层,其他层的盘子总会按从大到小的顺序在中转杆放置,
我们也不难看出,我们移动盘子到目标位置的过程中总是需要从起始杆->中转杆->目标杆这顺序,
这样我们就简化了代码,达到了大事化小的目的!!
ok!我们可以开始着手写代码了!!!!
#include<stdio.h>
void print(char x,char y)//打印步骤
{
printf("%c->%c ",x,y);
}
void move(int n,char start,char temp,char end)//变量为n层汉诺塔,起始杆'A',中转杆'B',目标杆'C'
{
if(n==1) //当只有一层汉诺塔时直接可以从起始移动到目标杆
{
print(start,end);
}
else
{
move(n-1,start,end,temp); //否则,将除底层外的盘子,以C杆作为中转杆移动到B杆
print(start,end); //此时起始杆上只有一个最大的盘子可以直接移动到C杆目标杆
move(n-1,temp,start,end); //最后再把B杆中作为起始杆,把B杆中剩余的盘子,经过A杆最后到达目标杆C杆结束整个搬运过程
}
}
int main()
{ int n =0;
scanf("%d",&n);
move(n,'A','B','C');
return 0;
}
四、如何权衡使用递归还是非递归:
如果用递归方式写起来很简单那用递归,或许是个不错的选择
如果用递归方式的运算效率十分慢那么,就要用非递归。
解决递归中“栈溢出”的问题
(本文章部分文字引用自网络,如侵权请联系删除)
以上为本人在学习C语言函数递归时的一些心得体会,希望本文章对您有所帮助!
如有错误需要修改,请在评论区联系我,谢谢。