目录
一、什么是递归函数
二、递归函数的原理
三、递归函数的优缺点
四、Python和C++递归函数例题讲解
1、递归函数求n!。
2、递归函数求正整数a和b的最大公约数。
3、汉罗塔问题。
五、递归函数需要注意的问题
一、什么是递归函数
1、如果通过一个对象自身的结构来描述或部分描述该对象,就称为递归。
2、递归函数即自调用函数,在函数内部直接或间接地自己调用自己,即函数的嵌套调用是函数本身。
二、递归函数的原理
1、递归函数之所以能够实现,关键是系统使用堆栈来保存函数调用中的传值参数、局部变量和函数调用后的返回地址。函数自身调用进行堆栈:系统把有关参数和地址压入堆栈,一直递推到满足终止条件,找到问题的最基本模式为止。然后进行回归:系统从堆栈中逐层弹出有关参数和地址,执行地址所指向的代码,一直到栈为空为止,问题得到解决。
补充:什么是堆栈。(数据结构里面的知识)
堆:是应用程序在运行的时候请求操作系统分配给自己内存,堆里面的内存需要在使用结束后自己释放。堆的空间较大但访问速度没有栈快。堆没有访问限制,不分先进后出还是先进先出。
栈:是操作系统在建立某个进程时或者线程时自动为这个线程建立的储存区域。使用完后系统自动回收内存。栈的空间较小,但访问速度快。栈有访问限制,必须先进后出,就像水杯里面的水,只有最上面的水出来下面的水才能出来。
2、构成递归函数的两个基本要素
递归步骤:描述的基本问题规模逐步缩小,若第一步为n那么第二步就是n-1依次类推直至到达递归调用的终止条件。
终止条件:递归算法和递归条件通常用条件语句表达,递归调用可以出现在执行语句中,也可以出现在判断表达式中。便于将递归结束,不再递归。(不然容易导致死循环。)
三、递归函数的优缺点。
优点:
1、递归使代码看起来更加整洁、优雅;
2、可以用递归将复杂任务分解成更简单的子问题;
3、使用递归比使用一些嵌套迭代更容易。
缺点:
1、递归的逻辑很难调试、跟进;
2、递归调用的代价高昂(效率低),因为占用大量的内存和时间。
四、Python和C++递归函数例题讲解
1、递归函数求n!。
n!的问题可以分成n!=n*(n-1)!,那么(n-1!=(n-1)*(n-2)!。依次类推问题的规模越来越小,最后到基本情况1!=1。不断递归下去,到递归结束条件后,再回归回来,将最终结果返回调用的函数。
当n=3,图示递归和回归过程。
c++编程n!
#include<iostream>
using namespace std;
int fact(int n)
{
if(n==0)
return 1;
else
{
return n*fact(n-1);
}
}
int main()
{
int n;
cout<<"输出几的阶乘:";
cin>>n;
cout<<n<<"的阶乘为"<<fact(n)<<endl;
return 0;
}
Python编程n!
def fact(n):
if n == 0:
return 1
else:
return n * fact(n - 1)
n=int(input("输出几的阶乘:"))
t=fact(n)
print(f"{n}的阶乘为{t}")
2、递归函数求正整数a和b的最大公约数。
从数学上可知,求a和b的最大公约数,等价于求b与a除以b所得余数的最大公约数。
例如:求a=24,b=16的最大公约数
b=16!=0
所有求a=24,b=16的最大公约数转换成a=16和b=(a%b)=8的最大公约数。
b=8!=0
所有求a=16,b=8的最大公约数转换成a=8和b=(a%b)=0的最大公约数。
b=0
所以a=8,b=0的最大公约数是8,即a=24,b=16的最大公约数就是8。
c++编程a和b的最大公约数
#include<iostream>
using namespace std;
int gys(int n,int m)
{
int g;
if(m==0) g=n;
else g=gys(m,n%m);
return g;
}
int main()
{
int a,b;
cout<<"求a为几和b为几的最大公约数:";
cin>>a>>b;
cout<<a<<"和"<<b<<"的最大公约数为"<<gys(a,b)<<endl;
return 0;
}
Python a和b的最大公约数
def gys(n,m):
global g
if m==0:
g=n
else:
g=gys(m,n%m)
return g
n=int(input("输入n的值:"))
m=int(input("输入m的值:"))
t=gys(n,m)
print(f"{n}和{m}的最大公约数为{t}")
3、汉诺塔问题。
传说印度的主神梵天在一个黄铜板上插了3根宝针,并在其中一根上从上到下按从小到大的顺序串上了64个金片。梵天要求僧侣们把金片全部移动到另一根针上去,规定每次只能移动一个金片,且不许将大金片压在小金片上。移动时可以借助第三根针暂时存放金片。梵天说,当这64个金片全部移至另一根针上时,世界就会在一声霹雳之中毁灭。
4个金片的汉诺塔示意
A,B,C代表3根宝石针,金片从小到大按顺序编号为1~n。
要将n个金片从A移动到C,必须要把最大的金片n从A移动到C,因此要先把1~n-1个金片移动B。
(以C为工具柱)
当金片n从A移动到C就无须再动,或者就当其消失了,剩下就是将1~n-1个金片中的n-1个金片从B移动到C。(以A为工具柱)
这时求解n阶汉诺塔问题,就变成了求解n-1阶汉诺塔问题,问题降了一阶。
总的来说:
1、先将n-1个金片从A柱移动到B柱。(C柱为工具柱)
2、将A上的最大金片移动到C柱上。
3、将B柱上n-2个金片移动到A柱上,将最大的移动到C柱上。
4、继续重复上面的操作,直至将所有的移动到C柱上。
这样就将大问题变成了不断缩小的子问题,递归的思想不太容易想清楚,但只要找清楚大问题与子问题之间的关系,其余的交给计算机来完成就行。
c++编程汉诺塔
#include<iostream>
using namespace std;
void Move(int n,char a,char b,char c)
{
if(n==1)//如果只有一个金片
cout<<a<<"-->"<<c<<endl;
else
{
Move(n-1,a,c,b); //把n-1个金片从A移动到B(以C为过渡)
cout<<a<<"-->"<<c<<endl;//将A柱上最大的移动到C柱
Move(n-1,b,a,c);//将B柱上的最大的金片n-1移动到C柱
}
}
int main()
{
int m;
cout<<"几层汉罗塔:";
cin>>m;
cout<<"挪动方式为:"<<endl;
Move(m,'A','B','C');
}
Python编程汉诺塔
def Move( n, a, b, c):
if n==1:
print(a,"-->",c)#如果只有一个金片
else:
Move(n-1,a,c,b)#把n-1个金片从A移动到B(以C为过渡)
print(a, "-->", c)#将A柱上最大的移动到C柱
Move(n-1,b,a,c)#//将B柱上的最大的金片n-1移动到C柱
m=int(input("几层汉罗塔:"))
print(Move(m,'A','B','C'))
五、递归函数需要注意的问题
1、必须设置终止条件
缺少终止条件的递归函数,将会导致无限递归函数调用其最终结果是系统会耗尽内存。
2、必须保证收敛
递归调用所解决子问题规模必须小于原始递归规模,则也会导致无限递归。
3、必须保证内存和运算消耗控制在一定范围,过量的递归函数会消耗过量的内存和运算能力。