一、递归之阶乘
假设你要计算数字n的阶乘。n的阶乘为n×(n-1)×(n-2)×┈×1,在数学领域的用途非常广泛。例如,计算将n个人排成一队有多少中方式。如何计算阶乘呢?可使用循环。
def factorial(n):
result = n
for i in range(1, n):
result *= i
result result
这种实现可行,而且直接了当。大致而言,它是这样的:首先将result。但如果你愿意,可采取不同的做法。关键在于阶乘的数学定义,可表述如下。
(1).1的阶乘的1。
(2).对于大于1的数字n,其阶乘为n-1的阶乘以n
如你所见,这个定义与本文开头的定义完全等价。
下面来考虑如何使用函数来实现这个定义。
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n - 1)
这是前述定义的直接实现。
二、递归之幂
假设假药计算幂,就像内置函数pow和运算符**所做的那样。要定义一个数字的整数次幂 ,有多种方式,先看一个简单的定义:power(x, n)(x的n次幂)是将数字x自乘n - 1次的结果,即将n个x相乘的结果。换言之,power(3, 3)是3自乘两次的结果,即3 × 3 × 3 = 27。
这实现起来很容易。
def power(x, n):
result = 1
for i in range(n):
result *= x
return result
这是一个简单的小型函数,但也可将定义修改成递归式。
(1).对于任何数字x,power(x, 0)都为1。
(2).n>0时,power(x, n)为power(x, n - 1)与x的乘积。
定义提供的结果与更简单的迭代定义完全相同。
def power(x, n):
if n == 0
return 1
else:
return x * power(x, n - 1)
三、递归之二分查找
一个常见的问题是:指定的数字是否包含在已排序的序列中?如果包含,在什么位置?为解决这个问题,可采取这样的策略:“这个数字是否在序列中央的右边?” 如果答案是否定的,再问:“它是否在序列的第二个四分之一区间内(左半部分的右边)?” 依次类推。明确数字所处区间的上限和下限,并且每一个问题都将区间分割成两半。
那么该如何做呢?
(1).如果上限和下限相同,就说明它们指向数字所在的位置,因此将此数字返回。
(2).否则,找出区间的中间位置(上限和下限的平均值),再确定数字在左半部分还是在右半部分。然后在继续在数字所在的那部分中查找。
在此递归案例中,关键在于元素是有序的。找出中间元素后,需要将其与要查找的数字进行比较即可。如果查找的数字更大,肯定在右边;如果更小,它必然在左边。
def search(seq, num, lower, upper):
if lower == upper:
assert num == seq[upper]
return upper
else:
middle = (lower + upper) // 2
if num > seq[middle]:
return search(seq, num, middle + 1, upper)
else:
return search(seq, num, lower, middle)
如果lower == upper,就返回upper,即上限。注意,这里假设(断言)找到的确实是要找到的数字(num == seq[upper])。如果还未找到基线条件,就找出中间位置,确定数字在它左边还是右边,再使用新的上限和下限递归地调用search。
为了方便调用还可以将上限和下限设置为可选的。为此,只需给参数lower和upper指定默认值,并在函数开头添加如下条件语句:if upper is None:upper = len(seq) - 1
完整代码如下:
def search(seq, num, lower=0, upper=None):
if upper is None:
upper = len(seq) - 1
if lower == upper:
assert num == seq[upper]
return upper
else:
middle = (lower + upper) // 2
if num > seq[middle]:
return search(seq, num, middle + 1, upper)
else:
return search(seq, num, lower, middle)
如果你调用函数时,序列是无序的请先对序列进行排序;也可在search函数的开头加上seq.sort()。
请注意!一定要注意!!!这里使用的序列一定要是有序的。