基础知识
递归的定义
在函数中调用函数自身的现象叫做递归。
递归的特点
1.一个问题可以分解成具有相同解决思路的子问题,这些问题都能够调用同一个函数
2.经过层层分解的子问题最后一定有一个不能再分解的固定值(即终止条件)。
递归的三大要素
要素一:函数的功能。
遇到递归函数的问题,首先应确定函数要实现的功能并定义该函数。
要素二:递归的结束条件。
确定递归的结束条件。此时既要求根据该参数能够直接得到结果,也要保证该结束条件不会使某些参数被漏掉。
要素三:函数的等价关系式
通过逐步缩小范围,找到函数的等价关系式(递推式),并将递推式写进函数。(但是切忌将子问题层层展开,会想晕,只要考虑这一层和其他层之间的关系即可)
递归的优化思路
1.减少重复计算
这是一种用空间换时间的优化方法。
对于f(n) = f(n-1) + f(n-2),递归调用状态图:
可以看到计算过程中产生了大量重复的子问题,耗费大量资源。为了优化递归,减少子问题的计算次数,可以用数组保存计算过的值,在递归过程中,当需要的结果已被计算过时,直接从数组中取值即可。
2.自底向上计算
这是一种节省空间的优化方法。
递归过程中,当从上往下递归时,递归过程中可能出现栈空间不足的问题,为了解决这一问题,有时我们在函数内进行循环,实现自底向上的计算,这样可以有效节省栈空间。
这种方法也被称之为递推(好像优化完也不算递归了hhh)
实战题
汉诺塔问题
题目
如下图所示,从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数。
解题思路
1.首先确定函数的功能,该函数的功能是将n个盘从a经由b挪到c,参数为n、a、b、c
2.找到递归终止条件,即n = 1时只需要将盘子从a移动到c
3.确定等价关系式,首先假设有两个盘子,则步骤为①将盘子1挪到b②将盘子2挪到c③将盘子1挪到c,然后将上面n-1个盘子看作整体,重复上述过程;解决n-1层汉诺塔移动问题时又可以将n-2个盘子看作一个整体……
递推式:move(n from a to c) = move(n-1 from a to b)+move( a to c) + move(n-1 from b to c)
代码
def hanoid(n:int,a,b,c): #将n个圆盘从a挪到c
if n == 1: #递归结束条件,n = 1时只需挪动一次
print(f'move {a} to {c}')
return 1
step1 = hanoid(n-1,a,c,b) #挪动n-1个圆盘到b
print(f'move {a} to {c}') #挪动最下面的圆盘
step2 = hanoid(n-1,b,a,c) #挪动n-1个圆盘到c
return step1+1+step2
n = input()
print(hanoid(int(n),'a','b','c'))