AI开发 - 算法基础 递归 的概念和入门(一) 递归算法的常见应用 PYTHON

一、递归的概念

在编程中,我们常常会遇到一个概念:递归。

递归是一个函数调用自身来解决问题的过程。你可以把它看作是“自我重复”的方法,用来分解复杂问题。

1. 举个例子:

想象你在一个楼梯上,每个台阶都有一个编号。如果你站在某个台阶上,要想知道距离地面多少个台阶,你可以做两件事:

  1. 看看自己前面(一个台阶)的台阶距离地面有多远。
  2. 然后,加上一个台阶的高度。

这个过程会一直重复下去,直到你到达楼梯的最底部,显然最底部的台阶距离地面是0。

这就是递归的一个典型应用:每个步骤都依赖于自己前一个步骤的结果。

递归的逻辑图 

2. 数学上的递归:

比如,计算阶乘(n!)就是一个递归的例子。阶乘的定义是:

  • 0! = 1
  • n! = n * (n-1)!

也就是说,n的阶乘等于n乘以(n-1)的阶乘,直到n=0时返回1。

3. 递归的关键点:

  1. 基准条件:递归必须要有一个停止的条件,通常是一个简单的、能直接解决的问题(比如上面提到的0! = 1)。
  2. 递归条件:问题要被分解为一个更小的子问题,直到基准条件触发。

4. 递归的实际代码:

def factorial(n):
    if n == 0:  # 基准条件
        return 1
    else:
        return n * factorial(n - 1)  # 递归条件

在这个例子中,factorial 函数会调用自己,直到 n 减小到 0。每一次递归都会计算一个较小的子问题,直到最简单的情况被解决。

递归的一个重要特点是它可以让程序代码更加简洁,尤其在处理一些分解式问题时非常有效,比如树的遍历、斐波那契数列等。

5. 递归的核心概念:

  1. 分解问题:递归通过将一个大问题分解为多个小问题来解决。每个小问题都可以通过相同的方式继续分解,直到它变得足够简单,可以直接解决。
  2. 回归(返回):递归过程需要一个返回的过程,当问题被分解到足够简单时,递归会逐步“回退”,并汇总答案。

6. 递归的结构:

  • 基准条件:递归必须有一个停止条件。没有停止条件的话,递归会无限进行下去,导致栈溢出错误。
  • 递归步骤:每次递归调用时,问题要缩小或简化(一般通过参数变化来实现)。

7. 经典的递归:斐波那契数列

斐波那契数列是一个由意大利数学家斐波那契(Fibonacci)提出的数列,定义为:从第三项开始,每一项等于前两项之和。其递推公式为:

  • F(0) = 0
  • F(1) = 1
  • F(n) = F(n-1) + F(n-2) (n ≥ 2)

例如,斐波那契数列的前几个数是:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

该数列在自然界中有许多应用,如植物的叶片排列、花瓣数目等。此外,斐波那契数列还在计算机科学中有重要应用,如动态规划、递归算法等。通过递归或迭代方式可以计算斐波那契数列的第n项,且其具有很高的数学和计算机理论价值。

递归实现斐波那契数列:

def fibonacci(n):
    # 基准条件
    if n == 0:
        return 0
    elif n == 1:
        return 1
    # 递归条件
    else:
        return fibonacci(n-1) + fibonacci(n-2)

# 测试递归函数
print(fibonacci(5))  # 输出 5

在这个示例中:

  1. 基准条件:当 n 为 0 或 1 时,直接返回结果(0 或 1)。
  2. 递归步骤:对于其他的 n,通过 fibonacci(n-1)fibonacci(n-2) 来计算。

比如,调用 fibonacci(5) 时,执行的步骤是:

fibonacci(5) = fibonacci(4) + fibonacci(3)
fibonacci(4) = fibonacci(3) + fibonacci(2)
fibonacci(3) = fibonacci(2) + fibonacci(1)
fibonacci(2) = fibonacci(1) + fibonacci(0)

最终结果是 5。 

有些人不理解为什么最终结果是5  不应该是0 或者1 吗?

这个问题问得很好!

实际上 递归函数自被使用后,它就有可能不止返回一次。比如 上面的这个例子,如果我们在返回1 的前面,加上“ print('return')” ,也就是打印一个标记,那我们在运行后就会发现:

你可以看到5次返回,每次都是返回1, 所以最终返回的值是5个1的聚合,就是5. 

这种递归方式虽然简洁,但效率较低,因为许多子问题被重复计算了多次。

如果我们在每个返回前都打印一个字符串return: “ print('return')”,我们会发现总共有15个返回。

上面的这些问题,我们可以通过 动态规划记忆化 方法来优化它。

8. 递归优化:记忆化

记忆化是一种优化递归算法的方法,通过缓存已经计算过的结果,避免重复计算。我们可以通过字典或数组来缓存每次计算的结果。

def fibonacci_memo(n, memo={}):
    if n in memo:
        return memo[n] #缓存放在这个字典(数组)里面,当下次有同样的n,不用计算了
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        result = fibonacci_memo(n-1, memo) + fibonacci_memo(n-2, memo)
        memo[n] = result
        return result

# 测试优化后的函数
print(fibonacci_memo(5))  # 输出 5

在这个版本中,我们引入了一个 memo 字典,它会缓存已经计算过的 fibonacci(n) 值。这样,当我们再次遇到相同的 n 时,就可以直接返回缓存的结果,避免重复计算。

二、递归的应用:

递归不仅仅用于数学问题,还广泛应用于很多领域,尤其是树形结构的遍历和分治算法。

递归在计算机科学和算法中有许多典型的应用,特别是在处理结构化数据(如树、图)或分治问题时非常有效。下面是一些常见的递归应用:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值