好久不见,递归法就是在函数中通过对自身函数的调用来求解特定结果,通常把一个大型的复杂问题,转化为与该复杂问题相似但规模更小的问题来求解。和递推相比,递归代码可读性更强
运用递归,主要需要考虑两个问题
①递归出口
②如何把一个复杂问题转化为多个简单问题
目录
先来两道简单题热热身(●ˇ∀ˇ●)
1.求解n!(n的阶乘)
递归法:
a=int(input())
def F(a):
if a<=1:
return 1
ans=a*F(a-1)
return ans
print(F(a))
递推法:
a=int(input())
ans=1
for i in range(1,a):
n=i+1
ans=ans*n
print(ans)
2.求解a的b次方
递归法:
a=int(input())
b=int(input())
def F(a,b):
if b==0:
return 1
elif b<0:
return 1/a*F(a,-b)
else:
return a*F(a,b-1)
print(F(a,b))
递推法:
a=int(input())
b=int(input())
ans=1
for i in range(b):
ans=ans*a
print(ans)
感觉到其中的奥妙了么?接下来这个问题会稍微复杂一些
3.汉诺塔问题。
当下有n个大小不同的圆盘,由大到小放在一个柱子上,现要将这些圆盘移动到另一个柱子上,一次只能移动一个圆盘,移动期间只能大圆盘在下小圆盘在上。提供一根辅助柱子帮助移动(也就是一共n个圆盘,3个柱子),设三个柱子分别为A、B、C,显示圆盘的移动过程如A->B
如图所示,我们可以把A看作所在柱子,C看作目标柱子,B为需要借助的柱子。因为整个过程只能大盘在下小盘在上的原则,要想把整个塔移动到C,一定是要先把最大盘上面的所有盘按从大到小的顺序放在B(A柱放现在最大盘,C柱子空着等待最大盘移入)。
若最大盘为n,其次大为n-1、然后n-2、n-3......1
那么我们接下来考虑的问题就是如何把n-1个盘子从A移动到B(n-1范围内的汉诺塔问题),那就需要包第n-1个盘子上面的所有盘按从大到小的顺序放在C(A柱放现在最大盘,B柱子空着等待最大盘移入),也就是把n-2 个盘子从A移动到C(n-2范围内的汉诺塔问题)......
所以,递归!
def move(n,A,B,C):
#递归出口
if n==0:
return
#先将n-1个盘子由大到小放在B上
move(n-1,A,C,B)
#将第n个盘子移动到C上
print("{}->{}".format(A,C))
#再将n-1个盘子由大到小放在C上)
move(n-1,B,A,C)
move(4,"A","B","C")
运行结果:
这里展示的是n为4的情况怎么样,是不是和预想的盘子移动顺序一样。不知道有没有人好奇代码
#将第n个盘子移动到C上
print("{}->{}".format(A,C))
n的取值不同,第一个盘子要移动的位置也不同,为什么一定确定是A到C呢,哈哈,一定要记住这里的A和C都是形参而不是实参
定义函数move(n,A,B,C)中的A、B、C也都是形参,分别代表着圆盘的“初始位置”、“暂留位置”、“目的位置”,所以它是很灵活的,让我们来看一看计算机具体每一步是如何处理的吧
进入函数move(n,A,B,C),在第六行代码开始递归,逐步查找n=3、n=2、n=1时move(n,A,B,C)的值无果,
move(4,A,B,C)
move(3,"A","C","B")
move(2,"A","B","C")
move(1,"A","C","B")
来到n=0,触及退出判断,退出语句move(0,"A","C","B"),来到move(1,"A","C","B"),中,执行下一句打印语句,这时A="A",C="B"
打印A->B
打印完成后执行下一语句,此时n=1,所以下一句执行的是move(0,"C","A","B")
触及退出判断退出语句move(0,"B","A","C"),就此move(1,"A","C","B")完成,来到move(2,"A","B","C")中的下一个语句----打印,此时A="A",C="C",n=2
打印A->C
然后执行下一个语句move(1,"B","A","C"),进入该语句的函数中又遇见了move(0,"B","C","A")返回,执行下一个打印操作
接着遇见move(0,"A","B","C"),返回。move(2,"A","B","C")就此完成,来到move(3,"A","C","B")。
之后就是重复的动作了,感兴趣的可以自己试一试。(不得不说这么繁多的步骤,还是看递归式更直观些,重在理解)
今天先到这里,明天继续练习,明天见~