# 4.1 程序控制结构

**程序控制结构**是指以某种顺序执行的一系列指令。无论多复杂的算法均可通过**顺序、选择、循环**三种基本控制结构构造出来。每种结构仅有一个入口和出口。由这三种基本结构组成的多层嵌套程序称为**结构化程序**。

### 4.1.1 控制结构

任何程序由三种基本结构组成：顺序结构，分支结构和循环结构。这些基本结构只有一个输入和输出。

**顺序结构**是程序按照线性顺序依次执行每一行语句的运行方式。

**分支结构**是程序在运行过程中遇到条件语句，经过运算根据结果的不同，执行不同语句的运行方式。根据分支结构分支数量不同，分支结构可分为**单分支结构**与**多分支结构**。

**循环结构**是程序在运行过程中遇到条件语句时判断是否对特定语句进行反复执行的运行方式。根据循环体触发条件不同，循环结构可分为条件循环结构和便利循环结构。

### 4.1.2 程序流程图

**程序流程图**是用来描述程序基本操作和控制流程的，由一系列图形、流程线和文字说明组成的一种方法。

#### 流程图基本要素

> **流程图**通常由4种基本元素：开始/终止框，数据框、决策框，处理框，流向线组成。在一些大规模应用场景，流程图还会使用联系框，注释框等元素。如图2.1 所示。

> 图2.1 流程图五种图形要素

> **开始/终止框**表示一个程序的开始和结束；

> **数据框**表示数据的输入或结果的输出；

> **决策框**对输入数据进行运算，判断运算结果是否满足预定条件，并根据判断结果，选择不同的执行路线。

> **处理框**：表示批处理。

> **流向线**指示程序的执行路径，通常使用带箭头的直线或曲线表示。

#### 流程图表示程序控制结构

程序基本结构：顺序结构、分支结构和循环结构都有一个入口和出口。

图4.2 是典型顺序结构的流程图。其中，

图4.2 顺序结构

图4.3 是典型分支结构的流程图。其中，

图4.3 单分支结构（左）与双分支结构（右）

图4.4 是典型循环结构的流程图。其中，

图4.4 条件循环结构（左）与遍历循环（右）

### 4.1.3 选择结构

**选择结构**是用于判断给定的条件，根据条件表达式的值为真（True）或为假（False），做出不同的决策，进而进行不同的分支路径选择。

条件语句是通过计算输入是否满足条件来对分支结构进行路径选择 。在Python里边通过使用if、elif、else等关键字来进行分支结构执行路径控制。

True和False是一对布尔（逻辑）变量，也可使用1和0表示。

#### if语句

if（if term）语句的作用是：对一个既给条件进行布尔判断，依据不同判断结果执行不同的语句。if语句通常有两种形式：一种不含有else分支，称为**单分支结构**，另外一种则含有一个或多个else分支，称为**多分支结构。**

单分支结构语句格式如下：

if term：

statement

含有else分支的单分支结构语句格式如下：

if term：

statement1

else:

statement2

多分支结构语句格式如下：

if term1:

statement

elif term2:

statement

elif term3:

statement

…

\[else :

statement3]

该语句在执行时，会首先判断第一个条件term1是否为真

选择结构图如图2.1.x所示

图：单分支结构图（左）与多分支结构图（右）

### 4.1.4 迭代结构

迭代语句是一种重复执行的程序结构。在实际应用中，经常需要对特定的代码进行重复执行，这时候就需要使用到迭代语句。常见的迭代语句有while语句和for语句。

#### while语句

while语句的一般语法如下：

while term：

statement #在编写单分支语句（选择结构或循环结构）时，可以将头部与循环体放在同

\#一行。此例可改写为while term: statement.

或者

while term:

statement1:

else:

statement2

以上两种while语句的流程图如2.1.x所示

图：while语句与while else语句

我们在使用while语句解决循环问题时，通常会遇到以下几种情况：

对于无限循环程序，如果不进行人为终止，那么程序就会一直运行，浪费系统资源。我们在编写无限循环程序时，往往会根据具体情况，增加循环条件，来对循环次数进行控制。

对于有限循环，自然终止的程序，又分为两种。一种，我们预先知道需要循环的次数，另外一种则是，我们预先不知道循环次数。对于这两种情况，我们就可以在关键词while后通过使用条件语句，对当前循环次数是否超出预定循环次数进行判别，从而对循环次数进行控制。

#### for语句

for语句的一般语法如下：

for elem in object：

statement #循环体可提至句头冒号后

或者

for elem in object：

statement1:

else:

for循环是python的一个通用序列迭代器：它可以遍历任何可迭代对象内的元素，如列表，字符串等。通常来说，for循环要比while循环执行的更快。

for循环首行指定了需要遍历的“容器”，并使用一个变量，在每次循环过程中，将容器里的元素的值逐一赋值给这个变量。在循环体中，可以对变量进行操作。

例：for循环遍历列表：

fruits=\[“Apple”, “Pear”, “Pineapple”, “Banana”]

for fruit in frutis:

print(x, end=’’)

例：for循环遍历字符串:

\>>>love\_python = “I love Python”

\>>>for letter in love\_python: print(letter, end=’ ‘)

IlovePython

例：for循环遍历元组：

\>>>love\_pyton=(“I”, “love”, “Python)

\>>>for letter in love\_python: print(letter, end=’ ‘)

I love Python

例：for循环遍历集合：

\>>>set={“Hust”, “ZZU”, “CS”, 408}

\>>>for elem in set: print(elem, end=’’)

408hustzzucs

我们在创建集合时的元素顺序与打印集合时元素的顺序不一致。

例：for循环遍历字典：

dic={“name”:”xiaoming”,”sex”:”male”,”age”:”20”};

for temp in dic.items():

print(temp)

for temp in user.items():

print(“key=%s, value=%s”,%(obj\[0], obj\[1]));

#### 跳转语句

在执行多层循环嵌套时，我们往往需要在完成既定目标的同时，又希望程序可以提前结束内层循环，甚至希望从外层结束所有循环。这时候，我们就需要使用到：break和continue语句。值得注意的是：break和continue语句只有在循环嵌套语句中才能起作用。

现在让我们考虑下面两种循环代码。

代码1

while term:

statement1:

if condition1:

continue

elif condition2:

break

else:

statement2

代码2

for elem in object：

statement1:

if condition1:

continue;

elif condition2:

break

else:

statement2

代码1和代码2分别使用了while else和for else语句。在循环体内，分别嵌套了两个单分支选择结构。在循环体执行过程中，加入condition1为真，那么，就会停止执行当前循环，直接进行下一轮循环。如果整个循环没有执行过elif condition2语句或执行过但是condition2不为真，那么在循环结束后，程序会执行else子句。如果在整个循环过程中，执行了elif condition2语句（也就意味着，在本次循环中，condition1为假），且condition2为真，那么层序将直接跳出循环，不执行else子句。

#### 占位语句

pass是空占位语句，它不做任何事情，只是为了保持程序结构的完整性。它通常用于为复合语句增加一个空的代码块。

代码清单2.1.x delete\_blank.py

for letter in "I love Python":

if letter==' ':

pass

else:

print(letter, end='')

该语句在执行过程中，如果遇到空格，就会自动进行下一轮循环。程序最终结果为I love Python.

除了使用pass语句占位外，还有一种更简洁的方式：使用“…”（三个点组成的省略号）占位。“…”除了可以用来占位以外，还可以不指定类型地对**变量名**进行初始化。

\>>>x=…

\>>>x

Ellipsis

#### 遍历技巧

通过前面的讲解，我们已经掌握了基本的选择结构与循环结构编写方法。下面我们将通过大量实例来对一些循环语句的编写技巧进行讲解。这些技巧将极大提高开发效率。

**range函数**

range函数可以创建一个整数列表。我们通过将range放入list函数中，才能显示它的所有内容。在for循环中，range则会自动产生结果，此时不需要使用list函数调用。

range函数的语法如下：

range(start, stop\[, step])

start：表示计数从start开始。默认为0。

stop：表示计数到stop结束，或者说到stop前一个数而不包括stop。

step：表示计数步长，默认为1。

range函数的所有参数都是整数，且可正可负。

例

\>>>list(range(10))

\[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

例：求

\>>>sum=0

\>>>for i in range(100, 0, -1):

sum+=i

\>>>print(sum)

5050

**zip函数**

python内置zip函数允许我们使用for循环并行访问多个序列。

zip函数的输入参数是一个或多个序列，它的返回值是这些序列并排的元素配对得到的列表。与range函数一样，zip函数返回一个可迭代对象，需要使用list函数才能显示其内容。

\>>>L1=\[1, 2, 3, 4, 5, 6, 7, 8]

\>>>L2=\[8, 7, 6, 5, 4, 3, 2, 1]

\>>>L3=\[1, 2,3 ,4 ,5 , 6, 7]

\>>>L4=zip(L1, L2)

\>>>L5=zip(L1, L2, L3)

L4, L5

(\<zip object at 0x0000020F89E83988>, \<zip object at 0x0000020F89E83788>)

我们使用zip函数将L1和L2列表中的元素进行组合得到L4。

\>>>list(L4)

\[(1, 8), (2, 7), (3, 6), (4, 5), (5, 4), (6, 3), (7, 2), (8, 1)]

当我们对L1, L2和L3列表进行配对形成新列表L5时，因为L3的元素个数小于L1和L2的元素个数，因此zip函数会选择最小序列长度来对结果元组进行截断。我们使用list函数来显示L5的内容。

\>>>list(L5)

\[(1, 8, 1), (2, 7, 2), (3, 6, 3), (4, 5, 4), (5, 4, 5), (6, 3, 6), (7, 2, 7)]

### 4.15 应用

1\. 实数绝对值：

输入一个实数n，给出这个实数的绝对值

程序清单3.1 real\_abs.py

a=input()

if a>0:

print(a)

elif a<0:

print(-a)

1.

使用泰勒展开公式，求e²取值，要求误差小于，并输出展开项个数。是自然对数。x²的泰勒展开式为。

程序清单 taylor\_expansion.py

error=float(“inf”) ##初始化误差最大化

n=0 #n项个数

temp=2 #幂

divisor=1 #除数

sum\_old=1

do

n++

i=1

for i\<n:

temp=temp\*2

i=i+1

for i>=n&\&i>1:

divisor=i\*(i-1)

sum\_new=sum\_old+temp/divisor

error=abs(sum\_new-sum\_old) #误差为新旧两个展开项之和的差值

sum\_old=sum\_new

while error>0.000001

print(“展开%d项时误差小于0.000001，此时e的取值为%d”%(n, sum\_new ) )

3\. 阶乘：

输入一个正整数n，求出这个正整数n的阶乘

n=input()

while n>1:

n=n\*(n-1)

else

print(n)

4\. 冒泡排序法（Bubble Sort）：

它重复地走访过要排序的元素列，依次比较两个相邻的元素，如果他们的顺序（如从大到小、首字母从A到Z）错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换，也就是说该元素列已经排序完成。

产生十个随机数，使用冒泡排序法对其进行自大到小排序。

程序清单3.4 bubble\_sort.py

import random

n=0

lis=\[]

while n<910

lis.append(random.random())

n+=1

print("排序前:", lis)

flag=0 #没有发生交换

for i in range(0, n, 1):

for j in range(n-1, i, -1):

if lis\[j]>lis\[j-1]:

lis\[j],lis\[j-1]=lis\[j-1],lis\[j]

flag=1 #发生了交换

if flag==0:

break

else:

pass #占位语句

print("排序后:", lis)

5\. 选择排序法（Selection Sort）：

选择排序（Selection sort）是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小（或最大）的一个元素，存放在序列的起始位置，然后，再从剩余未排序元素中继续寻找最小（大）元素，然后放到已排序序列的末尾。以此类推，直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。

对例题4中产生的随机数，使用选择排序法对其进行自小到大排序。

for i in range(0, n, 1):

index=i

for j in range(n-1, i,-1):

if lis\[index]>lis\[j]:

index=j

else:

pass

lis\[i], lis\[index]=lis\[index], lis\[i]

lis

程序清单3.2 selection\_sort.py

6\. 斐波那契数列（Fibonacci Sequence）

斐波那契数列（Fibonacci sequence），又称黄金分割数列、因数学家列昂纳多·斐波那契（Leonardoda Fibonacci）以兔子繁殖为例子而引入，故又称为“兔子数列”，指的是这样一个数列：1、1、2、3、5、8、13、21、34、……在数学上，斐波纳契数列以如下被以递推的方法定义：

prev=1

current=1

total=20

print(current)

for i in range(1, total+1):

print(current)

prev, current = current, prev+current
