Python编程四级 详细教案 ¶
对应教材:《Python编程入门与算法进阶》第17-21课 适用对象:已完成三级学习的学员 每节课时长:90分钟
第1课 函数的概念与意义 ¶
一、课程基本信息 ¶
- 课次:四级第1课
- 主题:函数的概念与意义
- 时长:90分钟
- 对应教材:第17课 函数的相关概念(17.3.1 函数的意义)
二、教学目标 ¶
知识目标 ¶
- 理解函数的概念和作用
- 掌握函数的定义语法(def关键字)
- 掌握函数的调用方法
- 理解函数执行的流程
能力目标 ¶
- 能够定义简单的无参函数
- 能够正确调用已定义的函数
- 能够将重复代码封装为函数
情感目标 ¶
- 体会函数带来的代码复用优势
- 培养模块化编程思维
三、教学重点与难点 ¶
- 重点:函数定义语法、函数调用、函数执行流程
- 难点:理解函数定义与调用的区别、函数的执行跳转
四、教学过程 ¶
(一)导入(10分钟) ¶
- 情景引入:如果要在程序中10次输出"欢迎来到编程世界",怎么做? - 方法1:写10行print(重复代码) - 方法2:用函数封装,调用10次
- 引出函数的概念:封装一段可重复使用的代码
- 生活中的函数类比:洗衣机(放入衣服→清洗→输出干净衣服)
(二)新知讲解(25分钟) ¶
-
什么是函数 - 函数是一段完成特定功能的代码块 - 可以接收输入(参数),可以返回输出(返回值) - 函数的作用:
- 代码复用(避免重复)
- 模块化(将大问题分解为小问题)
- 提高可读性(函数名即功能说明)
- 便于维护和调试
-
函数的定义
python def 函数名(参数列表): """函数文档字符串""" 函数体 return 返回值- def关键字:定义函数的标志 - 函数名:遵循变量命名规则,见名知意 - 参数列表:函数的输入(可以为空) - 冒号:定义结束的标志 - 函数体:缩进的代码块 - return:可选,返回结果 -
无参函数的定义与调用 ```python # 定义 def say_hello(): print("Hello, World!") print("欢迎学习Python函数")
# 调用 say_hello() ```
-
函数的执行流程 - 程序从上到下执行 - 遇到函数定义:只记录,不执行 - 遇到函数调用:跳转到函数体执行 - 函数体执行完:返回到调用处继续执行 - 流程图演示
-
函数定义的注意事项 - 函数必须先定义后调用 - 函数名不能与内置函数重名 - 函数体必须有缩进 - 空函数用pass占位
-
函数的文档字符串 - 用三引号写在函数体开头 - 说明函数的功能、参数、返回值 - 可以用help(函数名)查看
(三)动手实践(30分钟) ¶
任务1:定义并调用简单函数(8分钟)
# 定义一个打印分隔线的函数
def print_line():
print("=" * 30)
# 调用函数
print_line()
print(" 学生成绩管理系统")
print_line()
print("1. 添加学生")
print("2. 查询成绩")
print_line()
任务2:函数封装练习(10分钟) 将以下重复代码封装为函数:
# 原始代码(重复3次)
print("*" * 10)
print(" 菜单")
print("*" * 10)
# 要求:封装为print_menu()函数,调用3次
任务3:函数执行流程分析(12分钟) 阅读以下代码,写出执行顺序和输出结果:
def func_a():
print("开始执行A")
print("结束执行A")
def func_b():
print("开始执行B")
func_a()
print("结束执行B")
print("程序开始")
func_b()
print("程序结束")
- 学生先预测结果,再运行验证
- 教师讲解函数调用的栈执行过程
(四)小结与作业(25分钟) ¶
- 小结:函数概念、定义语法、调用方法、执行流程
- 易错点: - 函数定义后不会自动执行,必须调用 - 函数调用时不要忘记括号 - 函数必须先定义后调用 - 函数体缩进错误
- 作业: - 定义3个函数:打印欢迎语、打印菜单、打印结束语 - 编写一个程序,按顺序调用这3个函数 - 思考题:函数和循环有什么区别?各适合什么场景?
第2课 函数的参数 ¶
教学要点 ¶
- 重点:形参与实参、位置参数、关键字参数、默认参数
- 实践:带参函数编写、参数传递练习
- 易错点:参数个数不匹配、默认参数位置、可变对象作默认参数
核心知识点 ¶
-
形参与实参 - 形参(形式参数):函数定义时的参数 - 实参(实际参数):函数调用时传入的值 - 实参的值传递给形参
-
位置参数 - 按位置顺序传递 - 个数必须匹配 - 示例:
def add(a, b): return a + b,调用add(3, 5) -
关键字参数 - 按参数名传递 - 顺序可以任意 - 示例:
add(a=3, b=5)或add(b=5, a=3) -
默认参数 - 定义时指定默认值 - 调用时可以不传(使用默认值) - 默认参数必须放在非默认参数后面 - 示例:
def power(x, n=2): return x ** n -
位置参数与关键字参数混用 - 位置参数必须在关键字参数之前 - 示例:
func(1, 2, c=3) -
参数传递的本质 - 不可变对象(int/str/tuple):值传递 - 可变对象(list/dict):引用传递 - 函数内修改可变对象会影响外部
-
参数的类型提示(入门) -
def func(x: int, y: str) -> bool:
教学过程亮点 ¶
- 用"自动售货机"类比参数(投币=参数,出货=返回值)
- 默认参数的实用场景(设置默认选项)
- 可变对象作默认参数的陷阱演示
第3课 可变参数与匿名函数 ¶
教学要点 ¶
- 重点:args、*kwargs、lambda匿名函数、函数作为参数
- 实践:可变参数函数、lambda应用、高阶函数入门
- 易错点:args与*kwargs的区别、lambda只能写表达式、参数顺序
核心知识点 ¶
-
可变位置参数 *args - 接收任意多个位置参数 - 封装为元组 - 示例:
def sum_all(*args): return sum(args)- 调用:sum_all(1, 2, 3, 4, 5) -
可变关键字参数 kwargs** - 接收任意多个关键字参数 - 封装为字典 - 示例:
def print_info(**kwargs): for k,v in kwargs.items(): print(k,v)- 调用:print_info(name="小明", age=10) -
参数组合顺序 - 位置参数 → args → 默认参数 → *kwargs - 示例:
def func(a, b, *args, c=0, **kwargs) -
解包参数 - 列表/元组前加:解包为位置参数 - 字典前加*:解包为关键字参数 - 示例:
func(*[1,2,3])、func(**{"a":1}) -
匿名函数 lambda - 语法:
lambda 参数: 表达式- 没有函数名,只能写一个表达式 - 表达式结果就是返回值(不需要return) - 赋值给变量后可像函数一样调用 - 示例:square = lambda x: x * x -
lambda的应用场景 - 作为参数传递给高阶函数 - sorted的key参数:
sorted(list, key=lambda x: x[1])- map/filter的函数参数 - 简单的一次性函数 -
函数作为参数(高阶函数入门) - 函数可以作为参数传递 - 示例:
def apply(func, x): return func(x)- Python的函数是一等公民
教学过程亮点 ¶
- 用"万能接收器"类比args和*kwargs
- lambda与def定义函数的对比
- sorted自定义排序的实用案例(按字典某字段排序)
第4课 函数的返回值 ¶
教学要点 ¶
- 重点:return语句、返回单个值、返回多个值、返回列表/字典
- 实践:带返回值函数编写、函数结果使用
- 易错点:return后语句不执行、无return返回None、多返回值是元组
核心知识点 ¶
-
return语句的作用 - 将函数的结果返回给调用者 - 立即结束函数执行(return后的代码不执行) - 可以返回任意类型的数据
-
返回单个值
python def add(a, b): return a + b result = add(3, 5) # result = 8 -
返回多个值 - 用逗号分隔多个值 - 本质是返回一个元组 - 可以用多个变量接收(解包)
python def calc(a, b): return a + b, a - b, a * b s, d, p = calc(10, 3) -
返回列表/字典 - 返回复杂数据结构 - 用于批量数据处理
python def get_student(): return {"name": "小明", "score": 95} -
无返回值的函数 - 没有return语句 - 或return后没有值 - 返回None - 常用于执行操作(如打印)
-
return与print的区别 - print:输出到屏幕,函数外无法获取 - return:返回给调用者,可以继续使用 - 重要:不要用print代替return
-
返回值的使用 - 赋值给变量 - 作为其他函数的参数 - 参与表达式运算 - 函数嵌套调用
-
提前返回(early return) - 满足条件时立即返回 - 减少嵌套,提高可读性 - 常用于参数校验
教学过程亮点 ¶
- 用"自动售货机"类比返回值(投币→出货)
- return与print的对比实验(学生容易混淆)
- 多返回值的解包技巧
第5课 变量作用域 ¶
教学要点 ¶
- 重点:全局变量、局部变量、global关键字、nonlocal关键字
- 实践:作用域分析、变量修改练习
- 易错点:函数内修改全局变量需global、局部变量遮蔽全局、作用域查找顺序
核心知识点 ¶
-
变量作用域的概念 - 变量可以被访问的范围 - 不同作用域的变量互不干扰
-
全局变量(Global) - 定义在函数外部的变量 - 作用域:整个程序 - 所有函数都可以访问(读取)
-
局部变量(Local) - 定义在函数内部的变量 - 作用域:仅当前函数内部 - 函数外部无法访问
-
作用域查找顺序(LEGB) - Local(局部)→ Enclosing(嵌套)→ Global(全局)→ Built-in(内置) - 就近原则:先找局部,再找全局
-
局部变量遮蔽全局变量 - 函数内定义与全局同名的变量 - 函数内使用局部变量的值 - 不影响全局变量
-
global关键字 - 在函数内声明使用全局变量 - 可以修改全局变量的值
python count = 0 def increment(): global count count += 1 -
nonlocal关键字 - 在嵌套函数中使用外层(非全局)变量 - 用于闭包场景
python def outer(): x = 10 def inner(): nonlocal x x += 1 inner() return x -
global与nonlocal的区别 - global:修改全局变量 - nonlocal:修改外层函数变量(非全局)
-
函数参数的作用域 - 函数参数属于局部变量 - 函数外部不可访问
-
最佳实践
- 尽量减少全局变量的使用
- 函数通过参数和返回值与外界交互
- 全局变量常用于常量(全大写命名)
教学过程亮点 ¶
- 用"房间"类比作用域(全局=大厅,局部=房间)
- 演示:函数内读取全局变量vs修改全局变量
- global关键字的必要性实验(不写global会怎样)
第6课 函数参数类型注解 ¶
教学要点 ¶
- 重点:参数类型指定、返回值类型指定、类型提示
- 实践:类型注解编写、代码可读性提升
- 易错点:类型注解不强制检查、复杂类型注解、注解只是提示
核心知识点 ¶
-
类型注解的概念 - 在函数定义中指定参数和返回值的类型 - 提高代码可读性 - 帮助IDE提供更好的提示 - Python不强制检查(运行时不报错)
-
参数类型注解
python def greet(name: str): print(f"Hello, {name}") -
返回值类型注解
python def add(a: int, b: int) -> int: return a + b -
常见类型注解 - 基本类型:int、float、str、bool - 容器类型:list、dict、tuple、set - 特殊类型:None、Any、Optional - 函数类型:Callable
-
复杂类型注解 - 列表元素类型:
list[int](Python 3.9+) - 字典键值类型:dict[str, int]- 元组固定类型:tuple[int, str]- 可选类型:Optional[int](int或None) -
typing模块 - List、Dict、Tuple、Set(旧版本写法) - Union、Optional、Callable - Python 3.9+可直接用内置类型
-
类型注解的好处 - 文档作用:一看就知道参数类型 - IDE提示:自动补全更准确 - 静态检查:配合mypy等工具检查类型错误 - 团队协作:减少沟通成本
-
类型注解的注意事项 - 只是提示,运行时不强制 - 传错类型不会报错(除非用检查工具) - 不要过度使用,简单函数可不加 - 注解本身不影响性能
-
变量类型注解
python age: int = 10 name: str = "小明" -
类型注解的实际应用
- 公共API函数
- 复杂逻辑函数
- 团队协作项目
- 配合文档生成
教学过程亮点 ¶
- 演示IDE中类型注解带来的自动补全
- 类型注解与文档字符串的配合
- 讨论:什么时候该写类型注解
第7课 递归算法入门 ¶
教学要点 ¶
- 重点:递归概念、递归三要素、阶乘递归、斐波那契递归
- 实践:递归函数编写、递归过程分析
- 易错点:缺少基线条件导致无限递归、递归深度限制、递归效率
核心知识点 ¶
-
递归的概念 - 函数调用自身 - 把大问题分解为相同结构的小问题 - 生活中的递归:俄罗斯套娃、镜子对着镜子
-
递归的三要素 - 基线条件(Base Case):递归终止的条件 - 递归条件(Recursive Case):调用自身的条件 - 向基线条件靠近:每次递归问题规模减小
-
阶乘的递归实现
python def factorial(n): if n == 0 or n == 1: # 基线条件 return 1 return n * factorial(n - 1) # 递归条件- 数学定义:n! = n × (n-1)!,0! = 1 -
斐波那契数列的递归实现
python def fib(n): if n <= 1: # 基线条件 return n return fib(n - 1) + fib(n - 2) # 递归条件- 数列:0, 1, 1, 2, 3, 5, 8, 13... -
递归的执行过程 - 调用栈(Call Stack) - 每次调用压栈,返回出栈 - 以factorial(4)为例详细展开
-
递归与循环的对比 - 递归:代码简洁,思路清晰,但可能效率低、占内存 - 循环:效率高,但某些问题代码复杂 - 理论上递归和循环可以互相转换
-
递归的注意事项 - 必须有基线条件(否则无限递归→栈溢出) - Python默认递归深度限制(约1000层) - 递归可能有大量重复计算(如斐波那契) - 递归深度过大可能导致内存溢出
-
递归思维训练 - 如何把问题分解为子问题 - 找基线条件 - 找递归关系 - 从简单例子入手
-
简单递归问题 - 求和:1+2+...+n - 幂运算:x^n - 字符串反转 - 最大公约数(欧几里得算法)
教学过程亮点 ¶
- 用"俄罗斯套娃"直观理解递归
- 黑板演示factorial(4)的完整调用栈
- 斐波那契递归的重复计算问题(画递归树)
第8课 递归经典问题 ¶
教学要点 ¶
- 重点:汉诺塔、最大公约数、字符串反转、递归思维训练
- 实践:经典递归问题实现、递归过程可视化
- 易错点:汉诺塔的移动顺序、递归参数传递、基线条件设置
核心知识点 ¶
-
汉诺塔问题 - 问题描述:3根柱子,n个盘子,从A移到C,大盘不能在小盘上 - 递归思路:
- 将n-1个盘子从A移到B(借助C)
- 将第n个盘子从A移到C
- 将n-1个盘子从B移到C(借助A)
- 代码实现:
python def hanoi(n, a, b, c): if n == 1: print(f"{a} -> {c}") else: hanoi(n-1, a, c, b) print(f"{a} -> {c}") hanoi(n-1, b, a, c) - 移动次数:2^n - 1
-
最大公约数(欧几里得算法) - gcd(a, b) = gcd(b, a % b) - 基线条件:b == 0时返回a
python def gcd(a, b): if b == 0: return a return gcd(b, a % b) -
字符串反转 - 递归思路:第一个字符 + 反转剩余部分 - 基线条件:空字符串或单字符
python def reverse_str(s): if len(s) <= 1: return s return reverse_str(s[1:]) + s[0] -
回文字符串判断 - 递归思路:首尾字符相同,且中间部分也是回文 - 基线条件:长度<=1
-
二分查找的递归实现 - 递归思路:比较中间值,缩小范围递归 - 基线条件:找到或范围为空
-
递归求和/求最大值 - 列表求和:第一个元素 + 剩余列表的和 - 列表最大值:max(第一个元素, 剩余列表最大值)
-
递归的适用场景 - 问题定义本身是递归的(阶乘、斐波那契) - 数据结构是递归的(树、图) - 分治算法(归并排序、快速排序) - 回溯算法
-
递归调试技巧 - 打印递归深度和参数 - 从小规模输入开始测试 - 画递归树/调用栈 - 使用调试工具单步执行
-
递归优化入门 - 记忆化搜索(Memoization):缓存中间结果 - 尾递归(Python不优化) - 递归转递推/迭代
教学过程亮点 ¶
- 汉诺塔实物/动画演示(3个盘子的移动过程)
- 欧几里得算法的数学原理
- 递归问题的通用解题步骤
第9课 递推算法 ¶
教学要点 ¶
- 重点:递推思想、递推与递归对比、递推实现、动态规划入门
- 实践:递推问题编程、递推表构建
- 易错点:初始条件设置、递推公式、数组索引、空间优化
核心知识点 ¶
-
递推的概念 - 从已知条件出发,逐步推算出结果 - 利用前面的结果计算后面的结果 - 通常用循环实现
-
递推与递归的对比 | 特性 | 递归 | 递推 | |------|------|------| | 方向 | 从大到小(分解) | 从小到大(积累) | | 实现 | 函数调用自身 | 循环迭代 | | 效率 | 可能有重复计算 | 效率高 | | 内存 | 调用栈占用 | 数组/变量占用 | | 可读性 | 接近数学定义 | 需要理解推导过程 |
-
递推的三要素 - 初始条件(边界值) - 递推公式(状态转移方程) - 递推方向(从初始到目标)
-
斐波那契数列的递推实现
python def fib(n): if n <= 1: return n a, b = 0, 1 for _ in range(2, n + 1): a, b = b, a + b return b- 时间复杂度:O(n),空间:O(1) -
阶乘的递推实现
python def factorial(n): result = 1 for i in range(2, n + 1): result *= i return result -
动态规划入门 - 动态规划 = 递推 + 最优子结构 - 用数组保存中间结果(DP表) - 经典问题:爬楼梯、最大子段和
-
爬楼梯问题 - 问题:n级台阶,每次走1或2级,有多少种走法 - 递推公式:f(n) = f(n-1) + f(n-2) - 初始条件:f(1)=1, f(2)=2
python def climb_stairs(n): if n <= 2: return n dp = [0] * (n + 1) dp[1], dp[2] = 1, 2 for i in range(3, n + 1): dp[i] = dp[i-1] + dp[i-2] return dp[n] -
递推的空间优化 - 只需要前几个状态时,用变量代替数组 - 滚动数组技巧
-
递推问题的解题步骤 - 分析问题,确定状态 - 找初始条件 - 推导递推公式 - 确定递推顺序 - 编写代码 - 验证小例子
-
常见递推问题
- 杨辉三角
- 错排问题
- 整数拆分
- 最长递增子序列(入门)
教学过程亮点 ¶
- 递归与递推的执行过程对比动画
- 斐波那契:递归(指数级) vs 递推(线性) 的效率对比
- 动态规划DP表的填写过程演示
第10课 递归转递推 ¶
教学要点 ¶
- 重点:递归改递推方法、记忆化搜索、空间换时间优化
- 实践:递归函数改造、效率对比
- 易错点:递推顺序、初始条件、状态保存、边界处理
核心知识点 ¶
-
为什么要递归转递推 - 递归可能栈溢出(深度限制) - 递归可能有大量重复计算 - 递推效率更高,内存更可控 - 实际工程中递推更常用
-
递归转递推的通用方法 - 方法1:直接迭代(简单递归) - 方法2:记忆化搜索(自顶向下+缓存) - 方法3:动态规划(自底向上填表) - 方法4:手动模拟调用栈(复杂递归)
-
记忆化搜索(Memoization) - 递归 + 缓存已计算结果 - 用字典或数组保存 - 避免重复计算
python memo = {} def fib(n): if n in memo: return memo[n] if n <= 1: return n memo[n] = fib(n-1) + fib(n-2) return memo[n] -
自底向上的动态规划 - 从初始条件开始,逐步计算到目标 - 用DP表保存所有中间结果 - 与记忆化搜索结果相同,但实现方式不同
-
递归转递推的步骤
- 分析递归函数的参数和返回值
- 确定状态定义(DP表的含义)
- 找出初始条件(基线条件对应的值)
- 推导状态转移方程(递归公式)
- 确定计算顺序(确保依赖的状态已计算)
- 编写递推代码
-
验证结果与递归一致
-
案例1:斐波那契递归→递推 - 递归:fib(n) = fib(n-1) + fib(n-2) - 递推:dp[i] = dp[i-1] + dp[i-2] - 空间优化:只需两个变量
-
案例2:阶乘递归→递推 - 递归:fact(n) = n * fact(n-1) - 递推:result = 1; for i in 2..n: result *= i
-
案例3:杨辉三角递归→递推 - 递归:triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j] - 递推:逐行计算
-
递归与递推的选择 - 问题定义天然递归,且规模小 → 递归 - 需要高效率,大规模数据 → 递推 - 树/图遍历 → 递归(或显式栈) - 序列型DP → 递推 - 先写递归验证思路,再转递推优化
-
性能对比实验
- 斐波那契n=40:纯递归 vs 记忆化 vs 递推
- 运行时间对比
- 理解算法效率的重要性
教学过程亮点 ¶
- 现场计时对比三种实现的运行时间
- 记忆化搜索的缓存命中过程
- 递归树中重复节点的识别与消除
第11课 分治算法基础 ¶
教学要点 ¶
- 重点:分治思想、分治三步骤、归并排序原理
- 实践:分治问题分析、归并排序理解
- 易错点:分解边界、合并逻辑、递归深度、稳定性
核心知识点 ¶
-
分治算法的概念 - Divide and Conquer:分而治之 - 将大问题分解为多个相同结构的小问题 - 分别解决小问题,再合并结果 - 通常用递归实现
-
分治算法的三步骤 - 分解(Divide):将问题分解为子问题 - 解决(Conquer):递归解决子问题 - 合并(Combine):合并子问题的解
-
分治算法的适用条件 - 问题可分解为相同结构的子问题 - 子问题规模小到可以直接解决 - 子问题的解可以合并为原问题的解 - 子问题相互独立(不重叠)
-
归并排序(Merge Sort)原理 - 分解:将数组从中间分成两半 - 解决:递归对两半分别排序 - 合并:将两个有序数组合并为一个有序数组 - 基线条件:数组长度<=1时已有序
-
归并排序的合并过程 - 两个指针分别指向两个数组的开头 - 比较两个指针指向的元素,取较小的放入结果 - 移动指针,直到一个数组遍历完 - 将剩余元素直接加入结果
-
归并排序代码框架 ```python def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left = merge_sort(arr[:mid]) right = merge_sort(arr[mid:]) return merge(left, right)
def merge(left, right): result = [] i = j = 0 while i < len(left) and j < len(right): if left[i] <= right[j]: result.append(left[i]) i += 1 else: result.append(right[j]) j += 1 result.extend(left[i:]) result.extend(right[j:]) return result ```
-
归并排序的复杂度 - 时间复杂度:O(n log n) - 空间复杂度:O(n)(需要额外数组) - 稳定性:稳定排序
-
分治算法的经典应用 - 归并排序 - 快速排序 - 二分查找 - 大整数乘法 - 最近点对 - 汉诺塔
-
分治与递归的关系 - 分治是一种算法思想 - 递归是一种实现技术 - 分治通常用递归实现 - 但递归不一定是分治(如简单递归)
-
分治算法的分析方法
- 递归树分析
- 主定理(Master Theorem)入门
- 时间复杂度推导
教学过程亮点 ¶
- 用"分糖果"类比分治(把一大堆糖果分成小堆数,再汇总)
- 归并排序的合并过程动画/演示
- 归并排序与冒泡排序的效率对比
第12课 分治算法实现 ¶
教学要点 ¶
- 重点:归并排序代码、快速排序、分治问题分析
- 实践:分治算法编写、排序算法实现
- 易错点:快速排序的分区逻辑、pivot选择、边界处理、递归终止
核心知识点 ¶
-
归并排序完整实现与调试 - 代码逐行讲解 - 合并函数的细节 - 切片的空间开销 - 原地归并的优化(了解)
-
快速排序(Quick Sort)原理 - 分治思想的另一种应用 - 选择基准元素(pivot) - 分区(Partition):小于pivot的放左边,大于的放右边 - 递归对左右两部分排序 - 基线条件:数组长度<=1
-
快速排序的分区方法 - Lomuto分区方案(简单) - Hoare分区方案(高效) - pivot选择:首元素、尾元素、中间、随机
-
快速排序代码实现
python def quick_sort(arr): if len(arr) <= 1: return arr pivot = arr[len(arr) // 2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quick_sort(left) + middle + quick_sort(right) -
快速排序的复杂度 - 平均时间复杂度:O(n log n) - 最坏时间复杂度:O(n²)(已有序且pivot选端点) - 空间复杂度:O(log n)(递归栈) - 稳定性:不稳定排序
-
归并排序 vs 快速排序 | 特性 | 归并排序 | 快速排序 | |------|---------|---------| | 稳定性 | 稳定 | 不稳定 | | 最坏情况 | O(n log n) | O(n²) | | 空间 | O(n) | O(log n) | | 适用 | 链表、外部排序 | 数组、内部排序 | | 缓存友好 | 较差 | 较好 |
-
分治求最大值/最小值 - 分解:数组分两半 - 解决:分别求两半的最大值 - 合并:取两个最大值中的较大者
-
分治求逆序对 - 在归并排序的合并过程中统计 - 经典分治应用
-
分治算法的解题模板
python def divide_conquer(problem): # 基线条件:问题足够小,直接解决 if is_small(problem): return solve_small(problem) # 分解 subproblems = divide(problem) # 解决子问题 subresults = [divide_conquer(sp) for sp in subproblems] # 合并 return combine(subresults) -
分治算法的注意事项
- 子问题要相互独立
- 分解要均匀(避免最坏情况)
- 合并步骤要高效
- 注意递归深度
教学过程亮点 ¶
- 快速排序的分区过程演示(用扑克牌)
- 三种O(n log n)排序的对比(归并、快速、堆排序入门)
- 讨论:什么时候用归并,什么时候用快速
第13课 算法复杂度 ¶
教学要点 ¶
- 重点:时间复杂度、空间复杂度、大O表示法、复杂度分析
- 实践:算法复杂度计算、复杂度对比
- 易错点:大O的定义、常数项忽略、嵌套循环复杂度、递归复杂度
核心知识点 ¶
-
为什么需要算法复杂度 - 衡量算法效率 - 不同算法的优劣对比 - 预测算法在大规模数据下的表现 - 不依赖具体硬件和编程语言
-
时间复杂度的概念 - 算法执行时间随数据规模增长的趋势 - 用大O表示法(Big O Notation) - 关注增长趋势,不关注具体时间
-
大O表示法 - O(1):常数时间 - O(log n):对数时间 - O(n):线性时间 - O(n log n):线性对数时间 - O(n²):平方时间 - O(n³):立方时间 - O(2^n):指数时间 - O(n!):阶乘时间
-
大O的计算规则 - 只保留最高阶项 - 忽略常数系数 - 忽略低阶项 - 例如:3n² + 2n + 1 → O(n²)
-
常见操作的时间复杂度 - 基本运算(加减乘除、赋值):O(1) - 单层循环:O(n) - 嵌套循环:O(n²)、O(n³) - 二分查找:O(log n) - 排序:O(n log n)或O(n²)
-
时间复杂度分析方法 - 找出基本操作 - 计算基本操作执行次数 - 用大O表示 - 分析最坏情况、平均情况、最好情况
-
空间复杂度的概念 - 算法所需额外空间随数据规模的增长趋势 - 同样用大O表示 - 输入数据的空间不计入(额外空间)
-
常见空间复杂度 - O(1):常数空间(几个变量) - O(n):线性空间(数组、列表) - O(n²):二维数组 - O(log n):递归栈(分治)
-
递归算法的复杂度分析 - 递归树法 - 主定理 - 斐波那契递归:O(2^n)时间,O(n)空间 - 归并排序:O(n log n)时间,O(n)空间 - 二分查找递归:O(log n)时间,O(log n)空间
-
复杂度对比与选择
- 数据量小时:简单算法即可
- 数据量大时:必须考虑复杂度
- 时间与空间的权衡(空间换时间)
- 实际开发中的复杂度意识
教学过程亮点 ¶
- 用图表展示不同复杂度的增长曲线
- 现场实验:O(n) vs O(n²)在n=10000时的运行时间
- 算法优化的本质:降低复杂度阶数
第14课 算法优化策略 ¶
教学要点 ¶
- 重点:常见优化方法、空间换时间、预处理、剪枝优化
- 实践:算法优化案例、效率对比
- 易错点:过度优化、优化方向错误、边界条件处理
核心知识点 ¶
-
算法优化的目标 - 降低时间复杂度 - 降低空间复杂度 - 减少常数因子 - 在时间和空间之间权衡
-
优化的层次 - 算法层:换更好的算法(如O(n²)→O(n log n)) - 数据结构层:选择合适的数据结构 - 代码层:减少不必要的计算 - 系统层:利用硬件特性(了解即可)
-
空间换时间 - 用额外的存储空间减少计算时间 - 典型应用:
- 哈希表/字典:O(1)查找代替O(n)
- 缓存/记忆化:避免重复计算
- 预处理:提前计算好结果
- 示例:两数之和(用字典优化)
-
预处理优化 - 提前计算一些值,避免重复计算 - 前缀和数组:快速求区间和 - 后缀数组 - 预处理排序:多次查询时先排序 - 示例:前缀和求区间和
-
剪枝优化 - 在搜索/枚举中,提前排除不可能的分支 - 减少不必要的计算 - 应用场景:
- 枚举算法:缩小枚举范围
- 回溯算法:可行性剪枝、最优性剪枝
- 递归:提前返回
- 示例:百钱百鸡的范围优化
-
双指针技巧 - 用两个指针遍历,减少循环层数 - 有序数组的两数之和 - 滑动窗口 - 快慢指针 - 时间复杂度从O(n²)降到O(n)
-
数学优化 - 用数学公式直接计算代替循环 - 等差数列求和:n(n+1)/2 - 等比数列求和 - 解析算法代替枚举算法 - 示例:1到n求和(公式vs循环)
-
代码层面优化 - 减少循环内的重复计算 - 局部变量比全局变量快 - 避免不必要的类型转换 - 使用内置函数(通常用C实现,更快) - 列表推导式比for循环快 - 字符串拼接用join而不是+
-
递归优化 - 记忆化搜索(缓存) - 递归转递推/迭代 - 尾递归(Python不优化,了解) - 减少递归深度
-
优化的注意事项
- 先正确,再优化(不要过早优化)
- 优化后要验证正确性
- 用数据说话(profile分析瓶颈)
- 可读性与性能的平衡
- 不要为了微小的性能提升牺牲可维护性
教学过程亮点 ¶
- "两数之和"的三种解法对比(暴力O(n²)→排序O(n log n)→哈希O(n))
- 前缀和的实际应用
- 优化前后的运行时间对比实验
第15课 第三方库管理 ¶
教学要点 ¶
- 重点:pip命令、库的安装/卸载/查看、import与from导入
- 实践:第三方库安装、常用库使用入门
- 易错点:pip版本、虚拟环境、导入方式、库名与模块名区别
核心知识点 ¶
-
什么是第三方库 - Python标准库之外的库 - 由社区开发者贡献 - 功能丰富,避免重复造轮子 - Python的优势之一:丰富的生态
-
pip包管理工具 - Python的包管理器 - 安装Python时自带 - 用于安装、卸载、管理第三方库 - PyPI(Python Package Index):官方包仓库
-
pip常用命令 - 安装库:
pip install 库名- 指定版本:pip install 库名==版本号- 升级库:pip install --upgrade 库名- 卸载库:pip uninstall 库名- 查看已安装:pip list- 查看库信息:pip show 库名- 导出依赖:pip freeze > requirements.txt- 从文件安装:pip install -r requirements.txt -
pip的镜像源 - 官方源在国外,可能慢 - 国内镜像:清华、阿里、豆瓣 - 临时使用:
pip install -i 镜像地址 库名- 永久配置:修改pip配置文件 -
库的导入方式 -
import 模块名:导入整个模块- 使用:
模块名.函数名() from 模块名 import 函数名:导入特定函数- 使用:直接
函数名() from 模块名 import *:导入所有(不推荐)import 模块名 as 别名:导入并重命名from 模块名 import 函数名 as 别名
- 使用:
-
常用标准库回顾 - math:数学函数 - random:随机数 - time:时间相关 - datetime:日期时间 - os:操作系统接口 - sys:系统相关 - json:JSON处理 - re:正则表达式
-
常用第三方库介绍 - requests:HTTP请求 - numpy:数值计算 - pandas:数据分析 - matplotlib:数据可视化 - pygame:游戏开发 - pillow:图像处理 - jieba:中文分词 - beautifulsoup4:网页解析
-
第三方库使用流程
- 确定需求,找到合适的库
- 安装库(pip install)
- 导入库(import)
- 查阅文档,学习API
- 编写代码使用
-
记录依赖(requirements.txt)
-
模块化架构理解 - 模块(Module):一个.py文件 - 包(Package):包含多个模块的目录(有__init__.py) - 库(Library):相关包和模块的集合 - 框架(Framework):更大型的库集合
-
虚拟环境简介
- 不同项目可以有不同的库版本
- 避免版本冲突
- venv模块(Python自带)
- 了解概念即可,实际项目中使用
教学过程亮点 ¶
- 现场演示pip安装一个库(如pygame)并简单使用
- import的各种方式对比
- Python生态的丰富性展示(激发学习兴趣)
第16课 四级综合项目 ¶
项目主题:多功能计算器(函数+递归+分治) ¶
功能要求 ¶
- 基本运算:加、减、乘、除(函数封装)
- 高级运算: - 阶乘(递归实现) - 斐波那契数列(递归+递推两种实现对比) - 最大公约数(递归欧几里得算法) - 幂运算(递归分治实现)
- 排序功能: - 冒泡排序 - 归并排序(分治实现) - 快速排序(分治实现) - 三种排序效率对比
- 查找功能: - 顺序查找 - 二分查找(递归+迭代两种实现)
- 统计功能: - 平均值、最大值、最小值 - 方差、标准差 - 中位数
- 用户界面: - 菜单循环 - 输入验证(异常处理) - 结果格式化输出
技术要点 ¶
- 函数:自定义函数、参数、返回值、作用域
- 递归:阶乘、斐波那契、二分查找
- 递推:斐波那契递推实现
- 分治:归并排序、快速排序
- 算法优化:递归转递推、效率对比
- 第三方库:使用math库、statistics库
- 异常处理:输入验证
- 模块化:功能分函数,主程序清晰
模拟测试 ¶
- 选择题:函数概念、参数、返回值、作用域、递归、分治、复杂度、第三方库
- 判断题:概念辨析
- 编程题:3道(自定义函数、递归算法、分治排序)
知识串讲 ¶
- 函数概念:定义、调用、参数、返回值
- 参数类型:位置、关键字、默认、可变参数(args/*kwargs)
- 匿名函数:lambda表达式与应用
- 变量作用域:全局、局部、global、nonlocal
- 递归:三要素、经典问题、递归转递推
- 递推:动态规划入门、空间优化
- 分治:三步骤、归并排序、快速排序
- 算法复杂度:时间/空间复杂度、大O表示法
- 算法优化:空间换时间、预处理、剪枝、双指针
- 第三方库:pip管理、import导入、常用库
- 易错点汇总与答题技巧