递归函数

在前面的章节中,我们已经多次见到了函数调用其他函数的情况。而如果一个函数在内部调用了自身,那么这个函数就被称为递归函数。

是的,函数可以直接或间接地调用自己,这就形成了递归调用。你可能会问,这样不会导致无限循环,永远无法退出吗?实际上,递归函数必须具备终止条件,才能保证递归的结束。

让我们看一个经典的例子,高斯求和问题:1+2+3+4+…+99+100。如果不使用递归,我们可以通过循环来实现:

def sum_number(n):
    total = 0
    for i in range(1, n+1):
        total += i
    return total

sum_number(100)

但如果使用递归函数来写,是这样的:

def sum_number(n):
    if n <= 0:
        return 0
    return n+sum_number(n-1)

sum_number(100)

在这段代码中,我们对一个递归函数进行了分析。该函数用于计算从1到n的所有整数的和。

首先,我们需要注意基线条件,即当n小于等于0时,直接返回和值为0。这是递归的停止条件,避免了无限递归。

当n大于0时,我们使用递归调用sum_number(n-1)来计算n-1的和,并将其与n相加,得到最终结果。这里的递归调用意味着函数在内部调用自身,每次递归都将问题规模缩小,直到达到基线条件。

递归的核心思想是每一次递归都要将整体问题分解为更小的子问题,并最终得到结果。递归函数的实现通常遵循以下基本步骤:

  1. 初始化算法,通常需要一个起始值或参数。这个值可以作为递归计算的种子值。
  2. 检查当前值是否满足基线条件。如果满足,则进行相应的处理并返回结果。
  3. 使用更小或更简单的子问题来重新定义答案。
  4. 对子问题进行递归调用。
  5. 将子问题的结果合并到最终答案中。
  6. 返回最终结果。

递归函数的优点在于定义简单,代码量较少,逻辑清晰。虽然理论上所有的递归函数都可以使用循环方式实现,但递归能够更清晰地表达问题的逻辑。

有些同学可能认为递归并不简单,甚至更难理解。为了解释递归的概念,下面我们以一个树形结构的评论系统(如博主的博客评论系统)为例进行说明:

1--直接对文章的评论
    1.1--对评论1的回复
        1.1.1--对评论1.1的回复
        1.1.2--对评论1.1的回复
        1.1.3--对评论1.1的回复
    1.2 --对评论1的回复
        1.2.1--对评论1.2的回复
    1.3 --对评论1的回复   
2--直接对文章的评论
    2.1 --对评论2的回复
        2.1.1--对评论2.1的回复
    2.2 --对评论2的回复
3--直接对文章的评论
4--直接对文章的评论

请一定要注意,其中的1.1.1这种是方便大家理解评论层次,并不是真正的评论内容。每一个评论都有一个指向父评论的指针。现在的要求是,将所有的评论,根据评论的关系,放入一个列表内,然后逐一打印出来。需求的关键是我们必须穷举每个评论的子评论。下面我们写一个用循环来实现的伪代码:

lis = []
all_top_comments = ["顶级评论1","顶级评论2","顶级评论3","....."]
for comment in all_top_comments:
    for child_comment in comment:
        for child_child_comment in child_comment:
            for child_child_child_comment in child_child_comment:
                # ....子评论的子评论的子评论的....
                # 很快你就没办法写下去了,这种代码必定会被老板“重视”

你知道评论嵌套层级会有几层?有100层你就写100个for循环?对于这种问题,循环的做法是不行的。但是用递归就很简单了。

lis = []
all_top_comments = ["顶级评论1","顶级评论2","顶级评论3","....."]

def get_comment(comments):

    for comment in comments:
        lis.append(comment)
        child_comments = comment.child() # 假设有一个child方法获取当前评论的所有子评论。
        if len(child_comments) > 0:  # 如果有子评论的话,就递归查找下去,否则回退
            get_comment(child_comments)

get_comment(all_top_comments)

本博客的评论系统就是这么写的。

使用递归函数需要注意防止递归深度溢出,在Python中,通常情况下,这个深度是1000层,超过将抛出异常。在计算机中,函数递归调用是通过栈(stack)这种数据结构实现的,每当进入一个递归时,栈就会加一层,每当函数返回一次,栈就会减一层。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

标签: python, python下载, Python教程, Python技术, Python学习, Python学习教程, Python语言, Python开发, Python入门教程, Python进阶教程, Python高级教程, Python面试题, Python笔试题, Python编程思想