python版数据结构8、递归

目录

介绍

定义

特点

分类

单路递归

多路递归

斐波那契数列

兔子问题

问题优化

递归优化:记忆法/剪枝

爆栈问题

递归的时间复杂度公式

主定理

汉诺塔问题

思路

时间复杂度,T(n)=2T(n-1)+1=O(2^n)

python实现

杨辉三角

思路1、递归

算法流程

时间复杂度:O(2^N)

python实现

思路2、二维数组优化递归

算法流程

时间复杂度

python实现

思路3、迭代

算法流程

算法复杂度

python实现

思路4、动态规划优化迭代

算法流程

算法复杂度

python实现


  • 介绍

    • 定义

      • 深入到最里层叫做递
      • 从最里层出来叫做归
      • 在递的过程中,外层函数内的局部变量(以及方法参数)并未消失,归的时候还可以用到
    • 特点

      • 自己调用自己
      • 每次调用,会缩减问题规模,最后缩减至无需递归
      • 内层函数处理完成之后,外层函数才算调用完成
    • 分类

      • 将总数据分为两部分,已处理区域和待处理区域
      • 根据处理方向
        • 从前往后递归
          • 已处理区域在前,待处理区域在后
        • 从后往前递归
          • 直接根据数学公式来写
          • 可以缩减问题规模,更符合递归的特点
          • 待处理区域在前,已处理区域在后
        • 从后往前递归的代码比从前往后递归简洁,可以直接根据公式来写,但是思路更复杂,更难理解
      • 根据内部递归使用个数
        • 单路递归
        • 多路递归
  • 单路递归

    • 冒泡排序的递归实现,具体实现在:python数据结构5、排序_龙妞的博客-CSDN博客
    • 插入排序的递归实现,具体实现同上
    • 递归实现和迭代实现的区别
      • 递归实现简化了迭代实现的最外层循环,本质上和迭代实现没有区别
  • 多路递归

    • 斐波那契数列

      • 执行过程为二叉树
      • 递归次数符合规律:f(n)=2*f(n+1)-1
      • 时间复杂度:O(1.618^n)
    • 兔子问题

      • 问题描述
        • 有一对小兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。按此规律,假设没有兔子死亡,第一个月有一对刚出生的小兔子,问第n个月有多少对兔子?
      • 问题分析
    • 有几路,执行过程就是几叉树
    • python实现
    • def Fibonacci(n):
          if n <= 1:
              return n
          return Fibonacci(n - 1) + Fibonacci(n - 2)

    • 问题优化

      • 使用一个数组存储已经计算过的结果,进行剪枝
      • python实现
      • def Fibonacci2(n, cache):
            if n <= 1:
                cache[n] = 1
                return n
        
            if cache[n - 1] == -1:
                x = Fibonacci2(n - 1, cache)
                cache[n-1] = x
            else:
                x = cache[n-1]
        
            if cache[n - 2] == -1:
                y = Fibonacci2(n - 2, cache)
                cache[n-2] = y
            else:
                y = cache[n-2]
            return x + y

  • 递归优化:记忆法/剪枝

    • 存储每次递归的结果,后续再处理过程中,判断是否已经存在结果中,如果存在,则直接取值,实现了剪枝,否则执行递归
  • 爆栈问题

    • 尾递归
      • 函数最后一步是调用某个函数
    • 部分语言对尾递归进行了优化,在执行完一个函数之后,调用尾部函数之前,先释放当前函数所占用的内存,避免爆栈
    • 最好的方式,就是把递归改成循环
  • 递归的时间复杂度公式

    • 主定理

      • 条件1:T(n)=a \times T(\frac{n}{b})+f(n)
        • n,数据规模
        • a \times T(\frac{n}{b}),递归部分时间复杂度
          • a,子问题个数
          • T(\frac{n}{b}),子问题的运行时间,每个子问题被拆成原问题数据规模的n/b
        • f(n),非递归部分时间复杂度
      • 条件2:f(n)=O(n^c)
      • 则可套入公式
        • x=\log_b{a},即x=\log_{子问题缩小倍数}{子问题个数},a=b^x
        • T(n)=\begin{cases} O(n^x),c<x\\O(n^xlogn),c=x \\ O(n^c), c>x \end{cases}
    • 网站:hhtps://www.wolframalpha.com
  • 汉诺塔问题

    • 思路

      • 递归前提条件,n>=1
      • 目标,将罗盘从柱子A移动到柱子C
      • 移动过程
        • 将1~n-1视作一个整体进行移动,先将n-1通过C从A移动到B
        • 将n从A移动到C
        • 将n-1通过A从B移动到C
    • 时间复杂度,T(n)=2T(n-1)+1=O(2^n)

    • python实现

    • def HannoTower(n, A, B, C):
          if n == 0:
              return
          # 把n-1~1从A->B
          HannoTower(n - 1, A, C, B)
          # 把n从A->C
          print(f"move dish {n} from {A} to {C} ", end=': ')
          x = A.pop(0)
          C.insert(0, x)
          print(A, B, C)
          # 把n-1~1从b->c
          HannoTower(n-1, B, A, C)
      
      
      def HannoTower2(n, A, B, C):
          if n == 0:
              return
          # 把n-1~1从A->B
          HannoTower2(n - 1, A, C, B)
          # 把n从A->C
          print("move dish %d from %c to %c " % (n, A, C))
          # 把n-1~1从b->c
          HannoTower2(n-1, B, A, C)
      
      
      a = [1, 2, 3]
      b = []
      c = []
      n = len(a)
      print(a, b, c)
      HannoTower(n, a, b, c)
      HannoTower2(n, 'a', 'b', 'c')

  • 杨辉三角

    • 思路1、递归

      • 算法流程

        • 遍历每个元素的位置,双循环
          • 递归计算每个元素的值
            • 递归计算公式如下
            • f(i,j)=\begin{cases} 1,j=0| j=i \\ f(i-1,j)+f(i-1,j-1), others\end{cases}
            • 递归结束条件,j=0或j=i
            • 一次递归的返回结果,见公式
      • 时间复杂度:O(2^N)

      • python实现
      • def element(x, y):
            if y == 0 or y == x:
                return 1
            return element(x-1, y)+element(x-1, y-1)
        
        
        def YanghuiTriangle(n):
            # 递归法,O(2^N)
            for i in range(n):
                for j in range(i+1):  # 每行[0, i]
                    print(element(i, j), end=' ')
                print('')
        

    • 思路2、二维数组优化递归

      • 算法流程

        • 事先生成一个空的二维数组tris,用来存储递归过程中已经计算过的元素,方便进行剪枝
        • 遍历每个元素的位置,双循环
          • 递归计算每个元素的值
            • 递归计算公式如下
            • f(i,j)=\begin{cases} 1,j=0| j=i \\ f(i-1,j)+f(i-1,j-1), others\end{cases}
            • 递归结束条件,j=0或者j=i或者当前值已经计算过
            • 递归过程
              • 保存f(i-1, j-1)、f(i-1,j)、f(i,j)的值到二维数组中
            • 一次递归返回结果,f(i.j)
      • 时间复杂度

        • 因为添加了剪枝操作,所以时间复杂度大大降低
      • python实现
      • def element2(x, y, tris):  # 优化1,二维数组,空间代时间
            if y == 0 or y == x:
                tris[x][y] = 1
                return tris[x][y]
            if tris[x][y] != -1:  # 当前值已经计算过
                return tris[x][y]
            tris[x - 1][y - 1] = element(x - 1, y - 1)
            tris[x - 1][y] = element(x - 1, y)
            tris[x][y] = tris[x - 1][y] + tris[x - 1][y - 1]
            return tris[x][y]
        
        
        def YanghuiTriangle3(n):
            # 递归优化,二维数组,空间代时间,O(N^2)
            tris = []
            for i in range(n):
                ls = [-1] * n
                tris.append(ls)
            for i in range(n):
                for j in range(i+1):  # 每行[0, i]
                    print(element2(i, j, tris), end=' ')
                print('')
        
        

    • 思路3、迭代

      • 算法流程

        • 生成一个二维数组,用来存储结果
        • 遍历每一行,遍历范围为[1, n)
          • 先添加首元1
          • 遍历每一列,计算中间值,遍历范围为[1, i)
            • 利用之前的计算结果进行计算
          • 最后添加尾元1
      • 算法复杂度

        • 时间复杂度:O(N^2)
        • 空间复杂度:O(N^2)
      • python实现
      • def YanghuiTriangle2(n):
            # 迭代法,o(n^2),s(n^2)
            tris = [[1]]
            for i in range(1, n):
                tri = [1]
                for j in range(1, i):
                    tri.append(tris[i-1][j-1]+tris[i-1][j])
                tri.append(1)
                tris.append(tri)
            return tris

    • 思路4、动态规划优化迭代

      • 算法流程

        • 创建一个一维数组,用来存储每一行的数据
        • 遍历每一行,O(N)
          • 每次迭代只修改每行的数据,O(i)
      • 算法复杂度
        • 时间复杂度:O(N^2)
        • 空间复杂度:O(N)
      • python实现
      • def createRow(row, i):
            row.append(1)  # 先添加结尾元素1
            j = i - 1  # 从后往前修改数组的元素
            while j >= 1:  # j指针修改范围为[i-1, 1]
                row[j] += row[j - 1]
                j -= 1
        
        
        def YanghuiTriangle4(n):
            # 迭代优化,动态规划优化方法,一维数组,o(n^2),s(n)
            if n == 1:
                print(1)
                return
            row = [1]
            print(row)
            for i in range(1, n):
                createRow(row, i)
                print(row)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙妞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值