python入门篇-day09-补充递归

递归案例

入门

概述

在Python中, 我们把 函数自己调用自己的情况, 称之为: 递归.

注意事项:

  1. 递归必须要有出口, 否则容易造成: 死递归.

  2. 递归调用次数不能过多, 否则容易造成: 死递归.

  3. 搞定递归很简单, 只要分析清楚 出口规律即可.

示例代码

"""
递归简介:
    概述:
        在Python中, 我们把 函数自己调用自己的情况, 称之为: 递归.
​
    注意事项:
      1. 递归必须要有出口, 否则容易造成: 死递归.
      2. 递归调用次数不能过多, 否则容易造成: 死递归.
      3. 搞定递归很简单, 只要分析清楚 出口 和 规律即可.
"""
​
# 案例: 递归代码演示
​
# 1. 定义fun01()函数, 实现自己调用自己.
# 计数器
count = 0
def fun01():
    # 设置修改全局变量的值.
    global count
    count += 1
    # 正常打印
    print(f'我是 fun01 函数, {count}')
​
    # 出口
    if count >= 100:
        return
​
    # 函数自己调用自己 => 递归.
    fun01()
​
# 2. 在main方法中测试.
if __name__ == '__main__':
    # 调用 fun01()函数
    fun01()

阶乘

需求

"""
需求: 计算5的阶乘.
​
阶乘公式:
    5! = 5 * 4 * 3 * 2 * 1 = 5 * 4! = 120
即:
    n! = n * (n - 1)!
​
求5的阶乘, 思路分析:
    5! = 5 * 4 * 3 * 2 * 1          -------
         5 * 4!                       |
             4 * 3!                  规律
                 3 * 2!               |
                     2 * 1!         -------
                         1! = 1      出口
"""

代码

# 1. 定义函数 factorial(n), 用来计算 n的阶乘.
def factorial(n):
    # 出口, 1! = 1
    if n == 1:
        return 1
​
    # 规律
    return n * factorial(n - 1)
​
​
# 2. 在main方法中测试.
if __name__ == '__main__':
    result = factorial(5)
    print(f'result: {result}')  # 120

图解

不死神兔(斐波那契)

需求

案例: 不死神兔, 斐波那契数列.

介绍: 传说在很久很久以前, 有一个意大利青年, 叫: 斐波那契, 有一天, 他提出来一个非常有意思的问题: 1. 假设1对小兔子, 一个月之后会长成1对大兔子. 2. 每对大兔子, 每个月都会生1对小兔子. 3. 问: 假设所有的兔子都不死的情况下, 1对小兔子, 1年(即: 12个月)之后会变成多少对兔子?

分析流程: 月份 大兔子对数 小兔子对数 当月兔子总对数 1月 0 1 1 2月 1 0 1 3月 1 1 2 4月 2 1 3 5月 3 2 5 6月 5 3 8 ...... 12月 * * 144

大白话解释斐波那契数列: 已知数列: 1, 1, 2, 3, 5, 8, 13, 21... 问: 第12个整数是多少?

结论: 出口: 前两个月(第1月, 第2月)的兔子对数 = 1, 即: m = 1 or m = 2时, 兔子对数 = 1 规律: 从第3个月开始, 每月兔子对数 = 上月兔子对数 + 上上月兔子对数, 即: m月兔子对数 = (m-1)月兔子对数 + (m-2)月兔子对数

代码

# 1. 定义函数, 计算 month 月的兔子对数.
def get_rabbit(m):
    # 出口, 前两个月的兔子对数 = 1
    # if m == 1 or m == 2:
    # if m <= 2:
    if m in [1, 2]:
        return 1  # 兔子对数
    # 规律: m月兔子对数 = (m-1)月兔子对数 + (m-2)月兔子对数
    return get_rabbit(m - 1) + get_rabbit(m - 2)
​
​
# 2. 在main函数中调用
if __name__ == '__main__':
    # 思路1: 递归版.
    num = get_rabbit(12)
    print(f'第12个月的兔子对数为: {num} 对!')
    print('-' * 30)
​
    # 思路2: 用 列表 实现, 已知列表 rabbit_list = [1, 1], 后续的每个值 = 前两个值之和, 问: 列表的第12个值是多少?
    # 1. 定义列表, 记录 每月的兔子对数.
    rabbit_list = []
    # 2. 因为前两个月的兔子对数都是1, 我们手动添加即可.
    rabbit_list.append(1)
    rabbit_list.append(1)
    # 3. 从第3个值(即: 第3月开始)有规律了, 当月 = 前两个值之和.
    for i in range(2, 12):  # i(索引)的值: 2 ~ 12, 包左不包右, 即: 2 ~ 11 分别表示 3月 ~ 12月
        # 4. 规律: 当前值 = 前两个值之和.
        rabbit_list.append(rabbit_list[i - 1] + rabbit_list[i - 2])
    # 5. 打印结果.
    print(rabbit_list)
    print(f'第12个月的兔子对数为: {rabbit_list[11]} 对!')
    print(f'第12个月的兔子对数为: {rabbit_list[len(rabbit_list) - 1]} 对!')

爬楼梯

需求

需求: 假设需要爬n阶台阶才能到达顶层, 每次可以选择爬1阶或者2阶. 问: 共有几种方式可以到达顶层.例如: 到达顶层的楼梯总台阶数 你可以选择的具体的爬楼梯的方案 方案总数 1 1 1 2 11,2 2 3 21,12,111 3 4 1111,112,121,211,22 5 5 11111,1112,1121,1211,2111,122,212,221 8 ......结论: 出口: n=1 => 1 n=2 => 2 规律: n >= 3, n = (n - 1)的方案总数 + (n - 2)的方案总数

代码

# 1. 定义函数, 递归实现 计算爬楼梯总方案数.'
def climb_stairs(n):
    # 出口
    if n == 1:
        return 1        # 1个台阶, (爬楼梯)总方案数 = 1
    elif n == 2:
        return 2        # 2个台阶, (爬楼梯)总方案数 = 2
​
    # 规律
    return climb_stairs(n - 1) + climb_stairs(n - 2)
​
​
# 2. 在main函数中测试.
if __name__ == '__main__':
    # 思路1: 递归版.
    count = climb_stairs(6)
    print(f'爬楼梯总方案数为: {count}')
​
    # 思路2: for循环 + 列表版 实现. 
    # 列表爬楼梯
    steps = []
    steps.append(1)
    steps.append(2)
    for i in range(2, 11):
        # 当前楼梯的方案数 = 前面一级楼梯方案数 + 前面的前面一级的方案数
        steps.append(steps[-1] + steps[-2])
​
    print(steps[-1])

打印文件夹路径

需求

键盘录入1个文件夹路径, 打印该文件夹下所有文件(包括子文件夹)

出口: 如果是文件, 就打印, 不递归.规律: 如果是文件夹, 就递归.

代码

import os      # Operating  System, 系统模块, 里边定义的主要是和 文件, 文件夹(路径)相关的操作.
​
# 1. 定义函数 print_dir(path), 打印 path 文件夹路径下所有的子级.
def print_dir(path):
    """
    自定义函数, 打印path路径下 所有的子级, 包括子级的子级
    :param path: 要被打印的 文件夹路径
    :return: 无
    """
    # 1.1 判断path是否是 存在的 文件夹路径.
    if os.path.isdir(path):     # 假设: path = 'd:/src'
        # 1.2 走到这里, 说明是 存在的 文件夹路径, 就: 获取其所有的子级.
        child_names = os.listdir(path)  # ['aa', 'ai30', '代码打字练习词库.txt', '面试题.py']
        # 1.3 把上述的 子级文件(夹)的名字, 拼接成: 完整的 子级路径.
        for child_name in child_names:
            # 1.4 具体的拼接子级路径的动作, 即: 子级路径 = path + '/' + child_name
            child_path = path + '/' + child_name
            # 1.5 打印 子级路径
            print(child_path)
            # 1.6 判断当前的子级路径是否是 文件夹路径, 如果是文件夹, 就: 递归.
            if os.path.isdir(child_path):
                # 递归
                print_dir(child_path)
    else:
        # 1.3 走到这里, 说明路径非法.
        print('路径有误, 不是文件夹路径 或者 路径不存在, 程序结束!')
​
​
# 2. 在main方法中, 测试.
if __name__ == '__main__':
    print_dir('d:/src')

os模块常用函数

# 创建目录
os.mkdir('d:/aaa')
# 改名
os.rename('d:/aaa', 'd:/xyz')
# 删除目录, 必须是: 空目录
os.rmdir('d:/dest')
​
# 查看目录下, 所有的子级(不包括子级的子级), 只能获取: 子级的名字, 而不是子级的目录.
list_dir = os.listdir('d:/src')
print(type(list_dir))   # <class 'list'>
print(list_dir)         # ['aa', 'ai30', '代码打字练习词库.txt', '面试题.py']
​
# os.path.isdir(路径): 判断是否是 存在的 文件夹.
print(os.path.isdir('d:/src/aa'))   # 存在, 且是文件夹.        True
print(os.path.isdir('d:/src/bb'))   # 不存在.     False
print(os.path.isdir('d:/src/面试题.py'))   # 存在的, 但是是文件. False
print('-' * 30)
​
# os.path.isfile(路径): 判断是否是 存在的 文件
print(os.path.isfile('d:/src/面试题.py'))  # True, 存在, 且是文件.
print(os.path.isfile('d:/src/abc.py'))    # False, 不存在, 是文件.
print(os.path.isfile('d:/src/aa'))        # False, 存在, 是文件夹.
print('-' * 30)
​
# os.path.exists(路径): 判断是否是 存在的文件 或者文件夹.
print(os.path.exists('d:/src/面试题.py'))  # True, 存在的 文件
print(os.path.exists('d:/src/aa'))        # True, 存在的 文件夹.
print(os.path.exists('d:/src/bb'))        # False, 不存在的.
print('-' * 30)
​
# os.path.basename(路径):
print(os.path.basename('d:/src/面试题.py'))  # 面试题.py
print(os.path.basename('d:/src/1.py'))      # 1.py
print(os.path.basename('d:/src/aa'))        # aa
print(os.path.basename('d:/src/bb'))        # bb
print(os.path.basename('d:/ai30/base_class/hg/xyz'))    # xyz

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值