Python入门教程丨2.3 流程控制、算法效率分析及优化
流程控制是用于控制程序执行顺序的机制,它决定了程序中的语句按照何种顺序被执行。
本节课将详细讲解 Python 流程控制的三大核心结构:顺序、条件和循环,并配备一些小案例。
1. 顺序结构:从头到尾依次执行
顺序结构是程序中最基础的控制方式,代码会按照书写顺序从上到下逐行执行,没有任何跳转或判断。
例如我们用输出字符串的方式模拟一个日常活动,依次完成:
print("早上起床")
print("刷牙洗脸")
print("开始学习 Python 流程控制")
print("总结笔记并练习")
程序输出:
早上起床
刷牙洗脸
开始学习 Python 流程控制
总结笔记并练习
亦或是一个简易的计算器,给出两数进行加减乘除:
num1 = 10
num2 = 5
add = num1 + num2
subtract = num1 - num2
multiply = num1 * num2
divide = num1 / num2
print(f"加法结果:{add}")
print(f"减法结果:{subtract}")
print(f"乘法结果:{multiply}")
print(f"除法结果:{divide}")
2. 条件结构:让代码学会“拐弯”
条件结构通过判断条件是否成立,决定执行哪段代码,从流程图上看就是一个岔路口,不同的条件走不同的路线。
在 Python 中,条件控制结构主要有 if-else
和 match-case
两种形式,它们各自适用于不同场景。
2.1 if-else
我们首先来看较常用的if-else
。
语法格式:
if 条件:
执行语句1
elif 条件:
执行语句2
else:
其他情况
例如我们通过输入分数,判断学生的成绩:
score = int(input("请输入分数:"))
if score >= 90:
print("优秀!")
elif 70 <= score < 90:
print("良好!")
elif 60 <= score < 70:
print("及格!")
else:
print("不及格,请努力!")
又或者是输入三条边,判断是否能构成三角形,并判定类型:
a = int(input("请输入第一条边:"))
b = int(input("请输入第二条边:"))
c = int(input("请输入第三条边:"))
if a + b > c and a + c > b and b + c > a:
if a == b == c:
print("这是一个等边三角形!")
elif a == b or b == c or a == c:
print("这是一个等腰三角形!")
else:
print("这是一个普通三角形!")
else:
print("无法构成三角形。")
2.2 match-case
match-case
是 类似于其他语言中的 switch-case
。它适用于明确的值匹配或简单的模式匹配场景。
语法格式:
match 表达式:
case 情况1:
执行语句1
case 情况2:
执行语句2
case _:
默认执行语句
适用范围:
- 条件是固定值或简单的匹配模式,如具体的数值。
- 多个条件分支数量较多且独立。
例如我们按照星期安排活动:
day = input("请输入星期几(如星期天):")
match day:
case "星期一":
print("今天是周一,安排组会!")
case "星期二":
print("今天是周二,团队讨论!")
case "星期五":
print("今天是周五,准备周报!")
case _:
print("今天没有特别安排。")
3. 循环结构
循环结构可以让代码反复执行某些操作。Python 提供了两种主要循环:for
循环和 while
循环。
3.1 for 循环
for
循环是迭代式循环,用于遍历序列(如列表、元组、字符串等)中的每个元素,或者循环特定次数。
语法:
for 变量 in 可迭代对象:
执行语句
适用范围:
- 确定循环次数。
- 需要遍历序列中的每个元素。
例如计算列表元素的和
numbers = [1, 2, 3, 4, 5]
total = 0
for num in numbers:
total += num
print(f"列表的总和是:{total}")
嵌套循环指在一个循环内再包含另一个循环,适用于需要多层次迭代的场景。
经典案例:打印九九乘法表
for i in range(1, 10): # 外层控制行
for j in range(1, i + 1): # 内层控制列
print(f"{j}×{i}={i * j}", end="\t") # 使用制表符对齐
print() # 每行结束后换行
输出结果:
1 × 1 = 1
1 × 2 = 2 2 × 2 = 4
1 × 3 = 3 2 × 3 = 6 3 × 3 = 9
1 × 4 = 4 2 × 4 = 8 3 × 4 = 12 4 × 4 = 16
1 × 5 = 5 2 × 5 = 10 3 × 5 = 15 4 × 5 = 20 5 × 5 = 25
1 × 6 = 6 2 × 6 = 12 3 × 6 = 18 4 × 6 = 24 5 × 6 = 30 6 × 6 = 36
1 × 7 = 7 2 × 7 = 14 3 × 7 = 21 4 × 7 = 28 5 × 7 = 35 6 × 7 = 42 7 × 7 = 49
1 × 8 = 8 2 × 8 = 16 3 × 8 = 24 4 × 8 = 32 5 × 8 = 40 6 × 8 = 48 7 × 8 = 56 8 × 8 = 64
1 × 9 = 9 2 × 9 = 18 3 × 9 = 27 4 × 9 = 36 5 × 9 = 45 6 × 9 = 54 7 × 9 = 63 8 × 9 = 72 9 × 9 = 81
3.2 while 循环:灵活性更强的循环
while
循环是条件式循环,反复执行代码块,直到条件为 False
。
语法:
while 条件:
执行语句
适用范围:
- 循环次数不确定,但有明确的终止条件。
- 循环依赖某种动态计算的条件。
例子:猜数字游戏,并不能确保第几次猜对,就需要用 while 条件判断。
import random
secret_number = random.randint(1, 10)
attempts = 3
while attempts > 0:
guess = int(input("猜猜我是几(1-10):"))
if guess == secret_number:
print("恭喜你,猜对了!")
break
elif guess < secret_number:
print("小了!")
else:
print("大了!")
attempts -= 1
if attempts == 0:
print(f"很遗憾,正确答案是:{secret_number}")
3.3 break 和 continue循环控制语句
break
:提前结束循环。continue
:跳过本次循环,继续下一次。
例如需要过滤奇数
for i in range(10):
if i % 2 == 0:
continue
print(f"奇数:{i}")
4.时间复杂度与算法效率
在引入循环的概念后,我们就需要开始注重算法效率,循环在程序中往往会被反复执行,是性能瓶颈的主要来源之一。
而顺序结构是一次性执行的,运行时间是固定的,与输入规模无关。例如:
x = 5
y = x + 1
print(y)
无论输入规模多大,这些操作只执行一次,它们的时间复杂度是 O(1),无需深入分析。
循环执行的次数直接影响程序的运行时间,如果循环次数随着输入规模显著增加,会导致程序运行缓慢,甚至无法处理较大的输入。因此,分析循环的算法效率至关重要。
4.1 什么是时间复杂度?
时间复杂度是描述算法执行时间与输入规模之间关系的指标,用大O符号表示。例如:
- O(1) 表示操作的执行时间不随问题规模变化。
- O(n) 表示执行时间与问题规模成正比。
- O(n^2) 表示执行时间与问题规模成平方次比。
一般来说,一次循环的时间复杂度为 O(n),嵌套循环的时间复杂度为 O(n^2),当然具体问题需要具体分析,也有可能是 O(nlog2n)。但总体来说,嵌套循环会大大增加时间复杂度,编写程序时注意用其他方式替换来优化。
时间复杂度让我们预测程序在不同输入规模下的性能,从而评估其效率。
4.2 不同时间复杂度算法对比
我们用具体的例子来说明算法对时间复杂度的影响。
假设有两个数组:找到两个数组中和为目标值的所有数对arr1 = [1, 2, 3, 4]
arr2 = [3, 4, 5, 6]
目标是找出所有满足 x + y = 7 的数对。
1) 不使用嵌套循环解决问题(排序 + 下标)
我们可以先数组排序,然后使用两个下标(指针)来解决问题。
arr1 = [1, 2, 3, 4]
arr2 = [3, 4, 5, 6]
target = 7
# 排序两个数组
arr1.sort()
arr2.sort()
result = []
i, j = 0, len(arr2) - 1 # 设置两个下标,一个从 arr1 开始,一个从 arr2 末尾
while i < len(arr1) and j >= 0:
if arr1[i] + arr2[j] == target:
result.append((arr1[i], arr2[j]))
i += 1
j -= 1 # 找到匹配的后,同时移动两个下标
elif arr1[i] + arr2[j] < target:
i += 1 # 当前和小于目标值,增加较小的数字
else:
j -= 1 # 当前和大于目标值,减少较大的数字
print("结果:", result)
输出:
结果: [(1, 6), (3, 4)]
2) 使用嵌套循环解决问题
arr1 = [1, 2, 3, 4]
arr2 = [3, 4, 5, 6]
target = 7
result = []
for x in arr1: # 遍历第一个数组
for y in arr2: # 遍历第二个数组
if x + y == target: # 检查是否满足条件
result.append((x, y))
print("结果(嵌套循环):", result)
输出:
结果(嵌套循环): [(1, 6), (3, 4)]
4.3 算法效率分析:
在这个嵌套循环中,每个外层循环 n 次,内层循环 m次,时间复杂度为:O(nxm)=O(n^2)
若n = m = 1,000 ,循环次数=1,000×1,000=1,000,000,需要执行百万次操作。
当 n = m = 10^6 时,循环次数=10^6×10^6=10^12,需要执行万亿次操作。
而在不使用嵌套循环的算法中:
排序两个数组需要:O(nlogn+mlogm)
,遍历两个数组的时间复杂度为:O(n+m)
若 n = m = 1,000,排序时间约为 1,000log1,000≈10,000 次操作,遍历时间为 1,000+1,000=2,000次操作。
总循环次数=10,000+2,000=12,000,优化了 99% 以上的计算量。
若 n = m= 10^6,总循环次数=20,000,000+2,000,000=22,000,000,相比万亿级的计算量已经大大减少。
因此在编程时,我们要特别注意:
- 嵌套循环虽然简单直接,处理日常任务可以使用,但容易因指数增长导致效率低下。
- 在需要处理大规模数据时,应尽量避免嵌套循环,优化算法效率,减少不必要的重复计算。
5.小结
在本节中,我们一些重要的控制结构,重点是条件判断和循环。
⭐️ 循环结构用于重复执行代码,有 for 和 while 两种形式,适合不同场景。
⭐ 条件判断让程序具备决策能力,if-else 适合复杂逻辑,match-case 则简化多分支选择。
⭐ 算法效率与时间复杂度密切相关,循环的次数随数据规模增加而快速增长,优化代码能显著提高性能。