概念
通俗的来讲:递归就是调用自己。
满足条件
递归必须满足两个条件才可以使得程序正常进行。
1、基线条件
2、递归条件
基线条件:就是程序结束的条件,一般来讲递归程序都会在一个未知结束的情况中执行,所以你需要指定一个结束条件。指定函数从此不在调用自己,从而避免了死循环的情况。
递归条件:就是程序需要调用自己时的条件。
用一个示例来理解基线条件和递归条件,比如一个多少秒的倒计时打印输出:
def countdown(x):
time.sleep(1)
print(x)
# 这是一个基线条件,指定了程序在这个条件下结束
if x<=1:
return
# 这是一个递归条件,指明了,在这个条件下,程序会一直调用自己
else:
countdown(x-1)
countdown(5)
调用栈
前言:在递归过程中要理解这个概念,我们才能更好的理解递归过程中数据的变化。
栈的一大特点:先进后出。也就是说,最先进入栈的内容,会在最后才会弹出。(用一个栗子更好理解,比如说,我们有一个圆形柱状的盒子,我们用一堆和其直径大小相当的饼干,我们需要把这些饼干储存在这个盒子里面,我们就挨着放进去。当我们需要吃的时候,就从盒子表面一层一层吃完。放入饼干和取出饼干就如同,栈中的压如数据和弹出数据。)
在我们调用函数时,所有的好函数都会进入调用栈。
案例
下面通过一个案列来更好理解递归和调用栈。
求一个数的阶乘,我们有多种方式来处理,这里主要用递归来解释。
def fact(x):
if x==1:
return 1
else:
return x * fact(x-1)
如果按照正常的思路下来,你会发现,你的预期结果并不是理想的结果。预期结果除1外,其他的都会预期为x*(x-1),但是实际结果并不是如此的。
下面用一张图片来解释一下这个执行过程,就会很容易理解这段程序的执行结果。
总结:
1、递归有一个相当明显的缺点,栈会存储详尽的信息,如果栈很高,就会相当占用内存。这个时候我们可以使用循环来做。
2,、递归必须得满足有基线条件和递归条件。
3、在使用递归写复杂的程序时,代码简洁明了。
阶乘
当然,我们在求一个数的阶乘时,是不会使用上述的代码来完成的,下面介绍两种方式来求一个数的阶乘
1、调用math中的factorial
示例代码
def fafactorial(x):
return math.factorial(x)
2、利用函数reduce结合lamba
from functools import reduce
def fact_reduce(n):
return reduce(lambda x, y: x * y, range(1,n+1))