从0.1开始学Python——[14]
这是一个算任意数的阶乘的函数:
def jiecheng(n):
r = n
for i in range(1, n):
r *= i
return r
m = jiecheng(11)
print(m)
39916800
阶乘运算,它的运算过程就是从自身依次相乘减一的数,一直乘到1为止,算出总的结果。这个过程和今天要学的递归有一些相似之处。递归函数就是会在函数内部调用自己的函数。递归的基本思想就是把大问题分解为若干最基层的小问题,然后解决。一个可行的递归函数需要有两个条件:基线条件和递归条件。基线条件指的是可以被分解为的最小问题,分解到基线条件就停止递归了,就像阶乘在乘到1后就停了,因为1!=1不能再分解了;递归条件指的是将问题继续分解的条件,就像阶乘下一次相乘的数减一一样。
上面讲的阶乘函数,本质实际上也是递归函数。首先,基线条件是看n是否为1,到1了就不继续乘了。然后,递归条件就是n*(n-1)!,然后(n-1)!再分解为(n-1)*(n-2)!,直到基线条件。那么,怎么算(n-1)!呢,这就是在阶乘函数内部调用自己的过程,算n阶乘用jiecheng(n),那么算(n-1)阶乘不就是jiecheng(n-1)吗?
def jiecheng(n):
# 基线条件
if n == 1:
return 1
# 递归条件
return n * jiecheng(n-1)
r = jiecheng(11)
print(r)
39916800
递归函数更加方便看清代码的逻辑和意图。
编写递归函数,也就是找递归条件的关键在于拆分问题的过程,这个过程我们需要找出每次拆分都包含的相同形式的部分,这就是递归的部分。比如上面的阶乘问题,n!=n*(n-1)!,而(n-1)!=(n-1)*(n-2)!,每一次拆分都有相同形式,也就是阶乘的部分,于是这就是递归的部分。然后拆分到最后,1!=1,拆不动了,这就是基线条件。但是注意,由于基线条件是递归到最后才执行的条件,因此函数内部的判断语句应该把基线条件写在if后面,因为基线条件只运行一次,而其他递归步骤大多要运行多次,每次数值都不一样,所以直接放进else或elif的部分。下面两个练习(摘自尚硅谷):
幂运算练习:
def miyunsuan(n, i): # n为底数,i为幂数
if i == 1: # 基线条件,n的一次幂,结果就是n本身
return n
return n * miyunsuan(n, i-1) # 递归条件,n ** i = n * (n ** (i-1))
r = miyunsuan(6,5)
print(r)
7776
回文字符串检查:
def huiwen(s): # 回文字符串检查,正读反读一样就是
# 检查回文的关键在于正数第1个和倒数第1个字符一样不一样,一样就缩减最外层的两个字符再检查“新”字符串正数第1个和倒数第1个字符一样不一样
# 以此类推,这个就是递归的地方;然后最后剩下的字母,如果剩下一个,直接不用检查了,回文,检查结束,甚至偶数个最后剩0个,同样回文,这就是基线条件
if len(s) < 2:
return True
elif s[0] != s[-1]: # 由于这个判断和计算类的递归函数不一样,因此我们的基线条件需要有判断不是的选项
return False
# 这之后才能开始编写递归条件
return huiwen(s[1:-1]) # 缩减最外层的两个字符的过程,本质上是切片
# 其实递归条件写成return s[0] == s[-1] and huiwen(s[1:-1])是不错的选择,这样就不用在基线条件部分再加判断条件了,因为不满足and就会返回False
r = huiwen('hsh')
print(r)
True