## 第007课:分支和循环结构的应用
通过上两节课的学习,大家对Python中的分支和循环结构已经有了感性的认识。**分支和循环结构**的重要性不言而喻,它**是构造程序逻辑的基础**,对于初学者来说也是相对困难的部分。大部分初学者在学习了分支和循环结构后都能理解它们的用途和用法,但是遇到实际问题的时候又无法下手;**看懂别人的代码很容易,但是要自己写出同样的代码却又很难**。如果你也有同样的问题和困惑,千万不要沮丧,这只是因为你才刚刚开始编程之旅,**你的练习量还没有达到让你可以随心所欲的写出代码的程度**,只要加强编程练习,这个问题迟早都会解决的。下面我们就为大家讲解一些经典的案例。
### 经典小案例
#### 例子1:寻找水仙花数。
> **说明**:水仙花数也被称为超完全数字不变数、自恋数、自幂数、阿姆斯特朗数,它是一个3位数,该数字每个位上数字的立方之和正好等于它本身,例如:13 + 53 + 33 = 153。
这个题目的关键是将一个三位数拆分为个位、十位、百位,这一点利用Python中的`//`(整除)和`%`(求模)运算符其实很容易做到,代码如下所示。
```Python
"""
找出所有水仙花数
Version: 0.1
Author: 骆昊
"""
for num in range(100, 1000):
low = num % 10
mid = num // 10 % 10
high = num // 100
if num == low ** 3 + mid ** 3 + high ** 3:
print(num)
```
上面利用`//`和`%`拆分一个数的小技巧在写代码的时候还是很常用的。我们要将一个不知道有多少位的正整数进行反转,例如将`12345`变成`54321`,也可以利用这两个运算来实现,代码如下所示。
```Python
"""
正整数的反转
Version: 0.1
Author: 骆昊
"""
num = int(input('num = '))
reversed_num = 0
while num > 0:
reversed_num = reversed_num * 10 + num % 10
num //= 10
print(reversed_num)
```
#### 例子2:百钱百鸡问题。
> **说明**:百钱百鸡是我国古代数学家[张丘建](https://baike.baidu.com/item/%E5%BC%A0%E4%B8%98%E5%BB%BA/10246238)在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?翻译成现代文是:公鸡5元一只,母鸡3元一只,小鸡1元三只,用100块钱买一百只鸡,问公鸡、母鸡、小鸡各有多少只?
```Python
"""
《百钱百鸡》问题
Version: 0.1
Author: 骆昊
"""
# 假设公鸡的数量为x,x的取值范围是0到20
for x in range(0, 21):
# 假设母鸡的数量为y,y的取值范围是0到33
for y in range(0, 34):
z = 100 - x - y
if 5 * x + 3 * y + z // 3 == 100 and z % 3 == 0:
print(f'公鸡: {x}只, 母鸡: {y}只, 小鸡: {z}只')
```
上面使用的方法叫做**穷举法**,也称为**暴力搜索法**,这种方法通过一项一项的列举备选解决方案中所有可能的候选项并检查每个候选项是否符合问题的描述,最终得到问题的解。这种方法看起来比较笨拙,但对于运算能力非常强大的计算机来说,通常都是一个可行的甚至是不错的选择,只要问题的解存在就能够找到它。
#### 例子3:CRAPS赌博游戏。
> **说明**:CRAPS又称花旗骰,是美国拉斯维加斯非常受欢迎的一种的桌上赌博游戏。该游戏使用两粒骰子,玩家通过摇两粒骰子获得点数进行游戏。简化后的规则是:玩家第一次摇骰子如果摇出了7点或11点,玩家胜;玩家第一次如果摇出2点、3点或12点,庄家胜;玩家如果摇出其他点数则玩家继续摇骰子,如果玩家摇出了7点,庄家胜;如果玩家摇出了第一次摇的点数,玩家胜;其他点数玩家继续摇骰子,直到分出胜负。
```Python
"""
Craps赌博游戏
我们设定游戏开始时玩家有1000元的赌注
游戏结束的条件是玩家破产(输光所有的赌注)
Version: 0.1
Author: 骆昊
"""
from random import randint
money = 1000
while money > 0:
print(f'你的总资产为: {money}元')
go_on = False
# 下注金额必须大于0小于等于玩家总资产
while True:
debt = int(input('请下注: '))
if 0 < debt <= money:
break
# 第一次摇色子
# 用1到6均匀分布的随机数模拟摇色子得到的点数
first = randint(1, 6) + randint(1, 6)
print(f'\n玩家摇出了{first}点')
if first == 7 or first == 11:
print('玩家胜!\n')
money += debt
elif first == 2 or first == 3 or first == 12:
print('庄家胜!\n')
money -= debt
else:
go_on = True
# 第一次摇色子没有分出胜负游戏继续
while go_on:
go_on = False
current = randint(1, 6) + randint(1, 6)
print(f'玩家摇出了{current}点')
if current == 7:
print('庄家胜!\n')
money -= debt
elif current == first:
print('玩家胜!\n')
money += debt
else:
go_on = True
print('你破产了, 游戏结束!')
```
#### 例子4:斐波那契数列。
> **说明**:斐波那契数列(Fibonacci sequence),通常也被称作黄金分割数列,是意大利数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)在《计算之书》中研究在理想假设条件下兔子成长率问题而引入的数列,因此这个数列也常被戏称为“兔子数列”。斐波那契数列的特点是数列的前两个数都是1,从第三个数开始,每个数都是它前面两个数的和,按照这个规律,斐波那契数列的前10个数是:`1, 1, 2, 3, 5, 8, 13, 21, 34, 55`。斐波那契数列在现代物理、准晶体结构、化学等领域都有直接的应用。
```Python
"""
输出斐波那契数列前20个数
Version: 0.1
Author: 骆昊
"""
# 前两个数都是1
a, b = 1, 1
print(a, b, end=' ')
# 通过递推公式算出后面的18个数
for _ in range(18):
a, b = b, a + b
print(b, end=' ')
```
#### 例子5:打印素数。
> **说明**:素数指的是只能被1和自身整除的正整数(不包括1)。
```Python
"""
输出100以内的素数
Version: 0.1
Author: 骆昊
"""
for num in range(2, 100):
# 假设num是素数
is_prime = True
# 在2到num-1之间找num的因子
for factor in range(2, num):
# 如果找到了num的因子,num就不是素数
if num % factor == 0:
is_prime = False
break
# 如果布尔值为True在num是素数
if is_prime:
print(num)
```
### 简单的总结
还是那句话:**分支结构和循环结构非常重要**,是构造程序逻辑的基础,**一定要通过大量的练习来达到融会贯通**。刚才讲到的CRAPS赌博游戏那个例子可以作为一个标准,如果你能很顺利的完成这段代码,那么分支和循环结构的知识你就已经掌握了。
> **温馨提示**:学习中如果遇到困难,可以看看我们为大家录制的入门视频,视频的链接地址:,密码:4s6r,也可以加**QQ交流群**询问。
>
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
>
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。