第3章〓程序的控制结构 学习目标  掌握传统流程图或伪代码描述算法的方法。  掌握顺序结构、选择结构和循环结构的用法。 扫一扫 视频讲解 3.1程序设计的基本结构 3.1.1算法的描述 从广义上讲,算法是解决一个问题所采取的方法与步骤。常用自然语言、 传统流程图和伪代码表示算法。例如,怎样求一个三角形的面积? 图3.1求三角形面积的步骤 可以将这个问题分成三个步骤: 输入、处理过程和输出,即IPO(Input,Process,Output)模式,如图3.1所示。 IPO模式是系统分析和软件工程中广泛使用的方法,用于描述信息处理程序或其他过程的结构。 (1) 输入(Input): 主要包括从文件读入、控制台输入、随机数据输入、交互界面输入、网络输入和程序内部参数输入等几种方式。 (2) 处理过程(Process): 对输入数据的处理方法也称为“算法”,如求三角形的面积,可以用底乘高,再除以2,也可以用“海伦公式”,这是不同的算法。 (3) 输出(Output): 包括控制台输出、写出到文件中、网络输出以及操作系统内部变量输出等方式。 上面求三角形面积的例子是采用自然语言的方式描述算法的,但是对于复杂的问题,用自然语言描述时,如果程序发生多次跳转,则会降低程序的可读性。以下面三道例题为例,讲解描述算法的不同方法。 【例3.1】将变量a和b的值交换(a和b的初值为a=8,b=5)。 【例3.2】计算z的值,z=|a-b|(输入a、b的值)。 【例3.3】求1~5的累加和。 1. 自然语言 例3.1 S1: a=8,b=5 S2: a=5,b=8 S3: 输出a和b的值。 例3.2 S1: 输入a和b的值。 S2: 判断a>b? 是: S21: z=a-b, 转到S3步。 否: S22: z=b-a, 转到S3步。 S3: 输出z的值。 例3.3 S1: i=1, s=0 S2: 当i≤5时,执行 S21和S22,否则执行S3。 S21: s=s+i S22: i=i+1,执行S2。 S3: 输出s的值。 2. 传统流程图 常用的传统流程图的符号如表3.1所示。 表3.1传统流程图的符号 图形含义图形含义 起止框注释框 判断框流向线 处理框连接点 输入/输出框 用传统流程图表示例题结果如图3.2所示。 图3.2传统流程图 3. 伪代码 例3.1 a=8b=5 a=5b=8 print(a,b) 例3.2 input(a,b) ifa>=b then z=a-b else z=b-a endif print(z) 例3.3 i=1s=0 whilei<=5 s=s+i i=i+1 end print(s) 自然语言描述算法虽然简单,但当循环较多时,不易直观地表述清楚; 传统流程图比较直观,但当算法复杂时,传统流程图占篇幅较多,而且当程序转向较多时 ,难以阅读与修改。伪代码介于自然语言与计算机语言之间,用文字和符号描述算法,易于修改,其表达近似于编程语言,便于向程序过渡。 3.1.2三种基本结构 在图3.2中,三个流程图分别对应程序设计中的三种基本结构: 顺序结构、选择结构和循环结构。三道例题分别用Python实现的代码如下。 例3.1 a,b=8,5 a,b=b,a print(a,b) 例3.2 a = input('a=') b = input('b=') if a>=b: print(a) else: print(b) 例3.3 i=1 s=0 whilei<=5: s=s+i i=i+1 print(s) 扫一扫 视频讲解 3.2顺序结构 顺序结构是按照语句的先后顺序执行,几乎每个程序中都包含顺序结构。 【例3.4】将输入的摄氏温度转化为华氏温度。 c=float(input("请输入摄氏温度:")) f=9/5*c+32 print("华氏温度为:",f) #运行结果 请输入摄氏温度:30 华氏温度为: 86.0 input()函数的返回值是字符型,通过float()函数转换为实数类型并赋值给变量c。根据摄氏温度与华氏温度之间的转换公式计算对应的华氏温度并输出结果。 扫一扫 视频讲解 3.3选择结构 3.3.1单分支结构 单分支结构格式: if <表达式>: <语句块> 表达式可为算术表达式、关系表达式和逻辑表达式。当表达式成立时,执行语句块; 当表达式不成立时,则不执行语句块。 【例3.5】比较x和y的值,如果x>y,则输出x的值。 x,y=4,3 if x>y: print(x) 3.3.2双分支结构 图3.3双分支结构 双分支结构类似于当走到有两条分支的岔路口时, 只能选择其中一条岔路前进的情景,如图3.3所示。 双分支结构的格式: if <表达式>: <语句块1> else: <语句块2> 当表达式成立时,执行语句块1; 当表达式不成立时,执行语句块2。语句块中的语句由一条或多条语句组成,要注意缩进格式,如当语句块1由多条语句组成时,所有的语句同时缩进。 【例3.6】根据输入AQI的值,判断是否适宜户外运动。 AQI = eval(input("请输入PM2.5的值: ")) if AQI >= 75: print("不适宜户外运动") else: print("适宜户外运动") #运行结果 请输入PM2.5的值: 80 不适宜运动 其中input()函数的返回值是字符型。eval() 函数用于执行一个字符串表达式,并返回表达式的值。简单地理解为,eval()函数将input()的结果转化为数值赋给变量AQI。 3.3.3多分支结构 多分支结构类似于当面前有多条岔路时,只能选择其中一条岔路前进,如图3.4所示。 图3.4多分支结构 多分支结构的格式: if <表达式1>: <语句块1> elif <表达式2>: <语句块2> elif <表达式n>: <语句块n>  else: <语句块n+1> (1) 首先判断表达式1是否成立?如果成立,则执行语句块1。 (2) 当表达式1不成立时,判断表达式2是否成立?如果成立,则执行语句块2。同理,判断表达式n是否成立?如果成立,则执行语句块n。 (3) 如果前面的表达式都不成立,则执行语句块n+1。 【例3.7】求解分段函数。 y=1,x>0 0,x=0 -1,x<0 x=int(input("请输入一个数:")) if x>0: y=1 elif x==0: y=0 else: y=-1 print("y=",y) 这个分段函数有三种可能,分别是x小于0、x等于0、x大于0,在使用if…elif…else结构时,注意以下几点。 (1) 每个保留字后面有冒号“:”。 (2) else与if的配对原则: else与离它最近的未配对的if配对。 (3) 每个保留字后边的一条或多条语句的缩进层次相同。 3.3.4紧凑结构 if <表达式>: <语句块1> else: <语句块2> 分支选择的if…else…形式,可以写成等价的紧凑形式: <语句块1> if <表达式> else <语句块2> 紧凑形式的含义为,判断表达式是否成立,如果成立,则执行语句块1,否则执行语句块2。 【例3.8】if…else…紧凑形式示例一。 a,b=5,4 c = a if a>b else b print(c) #等价于 a,b=5,4 if a>b: c=a else: c=b print(c) 【例3.9】if…else…紧凑形式示例二。 count = 2 "存在" if count!=0 else "不存在"#如果count!=0成立,则显示"存在",否则显示"不存在" #运行结果 '存在' count = 0 "存在" if count!=0 else "不存在" #运行结果 '不存在' 扫一扫 视频讲解 3.4循环结构 循环结构类似于小朋友跳绳,将一个动作反复执行。Python中的循环语句主要包括for语句和while语句,同时常结合break语句和continue语句一起使用。 3.4.1for语句 for 语句常与保留字in一起使用,同时用range()函数控制循环次数。 1. range()函数用法一 range(start, stop[, step]),range()函数可以创建一个整数列表,一般用在for循环中。参数start,stop,step分别表示起始值、终止值、步长。range()函数的参数含义如表3.2所示。 表3.2range()函数的参数含义 参数 含义 start 起始值,缺省值为0 stop 终止值,循环变量不取stop的值 step 步长,缺省值是1 【例3.10】range()的用法示例。 在语句for i in range(5,10)中,5是起始值,10是终止值,默认步长是1。i的取值范围是5~9,不包括10。end=' '为控制数据输出时,以空格分隔,并显示在一行。 for i in range(5,10): print(i,end=' ') #运行结果 5 6 7 8 9 for i in range(0, 10, 3): print(i,end=' ') #运行结果 0 3 6 9 for i in range(-10, -100, -30): print(i,end=' ') #运行结果 -10 -40 -70 range(0,10,3)表示取值范围为0~10,以步长为3取值,得到一个等差数列。 2. range()函数用法二 格式: for循环变量 range (循环次数): 语句块 【例3.11】累加求和。 for i in range(1,10),i的取值范围为1~9,不包括10,即循环9次。for i in range(10),i 的取值范围为0~9,即循环10次,对i累加求和。 sum=0 sum=0 for i in range(1,10): for i in range(10): sum=sum+isum=sum+i print(sum)print(sum) #运行结果#运行结果 45 45 3.4.2while语句 格式: while <表达式>: <语句块1> else: <语句块2> while语句的表达式为真时,则执行语句块1,否则执行语句块2。While循环语句中,一般包含使循环趋于结束的语句,如i=i+1。 【例3.12】用while语句计算1~10的累加和。 i=1 sum=0 while i<11: sum=sum+i i=i+1 print(sum) #运行结果 55 思考: 修改程序,求1~10的奇数和、偶数和。 【例3.13】读程序,观察while…else中i值的变化。 i = 0 while i < 5: print(i, " is less than 5") i = i + 1 else: print(i, " is not less than 5") #运行结果 0isless than 5 1isless than 5 2isless than 5 3isless than 5 4isless than 5 5is not less than 5 一般情况下,for语句与while语句是通用的。当循环次数固定时,用for语句比较容易清晰地表示,例如,计算100~200的素数; 当循环次数不固定时,常用while语句,如计算1-1/3+1/5-1/7+…,直到某一项的绝对值小于10-6为止(该项不累加)。 3.4.3循环嵌套 当输出九九乘法表或画图案时,如钻石星形,用一个循环变量难以清晰地同时表示行和列,这时需要循环嵌套来解决问题。 【例3.14】输出4×4的乘法表的值。 for i in range(1,5): for j in range(1,5): print("{:<4d}".format(i*j),end=' ') print(' ') #运行结果 1234 2468 36912 481216 i控制行,j控制列,i和j的取值范围均是1~4。控制输出数据的输出格式,“<”表示左对齐,输出的数据宽度为4。end=' '表示数据间以空格分隔。 【例3.15】修改例3.14,只输出例3.14输出结果的下三角。 for i in range(1,5): for j in range(1,i+1): print(" {:d}".format(i*j),end=' ') print('') #运行结果 1 24 369 481216 3.4.4break与continue语句 break和continue语句一般与循环语句结合使用。break语句表示跳出当前循环; continue语句表示结束本次循环,进行下一次判断。 【例3.16】计算下列程序段的输出结果。 sum=0 for i in range(1,11): if i>5: break sum=sum+i print(sum) #运行结果 15   sum=0 for i in range(1,11): if i<=5: continue sum=sum+i print(sum) #运行结果 40 在例3.16中,第一个程序i取值范围为1~10,在i取值1~5时,执行累加。当i>5时,则跳出for循环。程序执行了5次循环,运行结果为15。第二个程序中,当i<=5时,不执行累加求和语句“sum=sum+i”,当i取值6~10时,执行累加求和语句“sum=sum+i”,运行结果为40。 【例3.17】字符串输出控制。 for ch in "Happy New Year!": if ch=="N": continue print(ch, end="") #运行结果 Happy ew Year! for ch in "Happy New Year!": if ch=="e": break print(ch, end="") #运行结果 Happy N 例3.17中,第一个程序中的变量ch遍历字符串Happy New Year!,当ch=="N"时,结束本次循环,然后ch取e值,进入下一次循环,直至循环结束,因此运行结果中不包含字符N。第二个程序中的变量ch遍历字符串Happy New Year!,当ch=="e"时,跳出循环,因此运行结果为Happy N。 扫一扫 视频讲解 3.5实例 【例3.18】“水仙花数”是指一个三位数,其各位数字的立方之和等于该数本身,例如,153=13+53+33。判断数字153是否为水仙花数。 这是一个典型的数字分离问题,需要把每一位从数中分离出来,百位为n//100,十位为n//10%10,个位是n%10取余数。 n=153 i = n // 100 j = n // 10 % 10 k = n % 10 if n == i*i*i + j*j*j + k*k*k: print("{:d}是水仙花数".format(n)) else: print("{:d}不是水仙花数".format(n)) #运行结果 153是水仙花数 【例3.19】求解分段函数。 有如下分段函数: y=|x|+1,x<0 x2+1,0<x<1 2x-1,x>1 编写程序,输入自变量x的值,计算y的值并输出。 import math x=eval(input("请输入数据:")) if x<0: y=abs(x)+1 elif x>0 and x<1: y=x**2+1 else: y=math.sqrt(2*x)-1 print(y) 【例3.20】输入一行字符,分别统计其中字母、空格、数字和其他字符的个数。 isalpha()方法用于检测字符串是否只由字母组成。isspace() 方法用于检测字符串是否只由空格组成。isdigit()方法用于检测字符串是否只由数字组成。 import string s = input('请输入一个字符串:') letters,space,digit,others = 0,0,0,0 i=0 while i < len(s): #len( )返回字符串长度 k = s[i] i += 1 if k.isalpha( ): letters+=1 elif k.isspace( ): space+=1 elif k.isdigit( ): digit+=1 else: others+=1 print('letters = %d,space = %d,digit = %d,others = %d' % (letters,space,digit,others) ) 【例3.21】冒泡法排序,将列表[9,6,5,3,1]中的数值从小到大排序。 arr = [9,6,5,3,1] n=len(arr) for i in range(n-1): for j in range(0,n-i-1): if arr[j] > arr[j+1] : arr[j], arr[j+1] = arr[j+1], arr[j] print(arr) #运行结果 [1, 3, 5, 6, 9] 冒泡法解题思路: 将相邻的两个数进行比较,小数放前面,大数放后面。经过几轮比较与交换位置,将排序后的结果输出,如图3.5所示。 图3.5冒泡法排序 例如,有5个数9,6,5,3,1。 第一轮: (1) 第一次是9和6比较,根据解题规则(两两比较,小数放前,大数放后), 9>6,6放在9前面,5个数的顺序变成6,9,5,3,1。 (2) 第二次是9和5比较,9>5,5放在9前面,5个数的顺序变成6,5,9,3,1。 (3) 第三次是9和3比较,9>3,3放在9前面,5个数的顺序变成6,5,3,9,1。 (4) 第四次是9和1比较,9>1,1放在9前面,5个数的顺序变成6,5,3,1,9。 这样,在第一轮中,找到了5个数中的最大数9。 第二轮: 6,5,3,1,比较方法同第一轮,找到第二大数6。 第三轮: 5,3,1,同理,找到第三大数5。 第四轮: 3,1,同理,找到第四大数3。 说明: (1) 轮数: 如果用n表示数的个数,比较的轮数就是n-1,如n=5,5个数比较n-1轮,即4轮。 (2) 每一轮比较次数: n-i-1,i是循环变量,取值0~3。 (3) arr[j],arr[j+1]=arr[j+1],arr[j],两个变量的值交换,这里不再赘述。 3.6习题 一、 单选题 1. 下列Python保留字中,不用于表示分支结构的是()。 A. elifB. inC. ifD. else 2. 实现多路分支的控制结构是()。 A. ifB. tryC. if…elif…elseD. if…else 3. 下列选项中,能够实现Python循环结构的是()。 A. loopB. do…forC. whileD. if 4. 关于Python的循环结构,下列选项中描述错误的是()。 A. break用来跳出最内层for或while循环,程序从循环代码后继续执行 B. 每个continue语句只能跳出当前层次的循环 C. 遍历循环中的遍历结构可以是字符串、文件、组合数据类型和range()函数等 D. continue结束整个循环过程,不再判断循环的执行条件 5. 执行下列代码,下列选项中描述正确的是()。 sum=0 for i in range(1,11): sum += i print(sum) A. 循环内语句块执行11次 B. 输出的最后一个数是66 C. 如果print(sum) 语句不缩进,输出结果不变 D. 输出的最后一个数是55 6. 关于Python 的控制结构,下列选项中描述错误的是()。 A. 每个 if 条件后要使用冒号“:” B. 在Python中,没有switch…case语句 C. Python中的pass是空语句,一般用作占位语句 D. elif可以单独使用 7. 执行下列语句,a、b、c 的值分别是()。 a = "water" b = "juice" c = "milk" if a > b: c = a a = b b = c A. water juice milkB. water milk juice C. juice milk waterD. juice water water 8. 执行下列代码,输出结果是()。 for s in "Hello,Python": if s=="P": continue print(s,end="") A. HelloB. Hello,ythonC. Hello,PythonD. Python 9. 执行下列代码,输出结果是()。 for s in " Hello,Python": if s=="P": break print(s,end="") A. Hello,B. Hello,ythonC. Hello,PythonD. Python 10. 执行下列代码,输出值的个数是()。 num=11 start=1 if num%2!=0: start=1 for x in range(start,num+2,2): print(x) A. 6B. 7C. 11D. 10 二、 编程题 1. 从键盘输入 3个数作为三角形的边长,输出由这 3条边构成的三角形的面积(保留两位小数)。 2. 编程实现: 学习成绩大于或等于90分用A表示,60~89分用B表示,60分以下的用C表示。 3. 编程实现: 判断输入的一个整数能否同时被3和7整除,若能整除则输出Yes,否则输出No。 4. 编写程序,根据输入的年份(4位整数)判断该年份是否为闰年。 5. 编程实现: 一个简单的出租车计费系统,当输入行程的总里程时,输出乘客应付的车费(保留一位小数)。计费标准具体为起步价10元/3km,超过3km的费用为1.2元/km,超过10km的费用为1.5元/km。 6. 编程实现: 输出1~100的奇数。 7. 编程实现: 数字逆序输出,从控制台输入三位数,如123,逆序输出321。 8. 编程求解: 有四个数字1、2、3、4,能组成多少个互不相同且无重复数字的三位数?请写出结果。 9. 编程实现: 求1+2!+3!+…+20!。 10. 编程实现: 有一分数序列2/1,3/2,5/3,8/5,13/8,21/13,…,求这个数列的前20项之和。 11. 编程实现: 输出钻石图形。 * *** ***** ******* ***** *** * 12. 编程实现: 用for循环输出九九乘法表。 13. 编写程序,输出斐波那契数列的前20项,要求每行输出5项。 14. 编程实现: 输出100~1000的所有水仙花数。 15. 编写程序,计算s=a+aa+aaa+…+aaa…aaan个的值,a为1~9中的某个数字,n是一个正整数。例如,当a=2,n=5时,s=2+22+222+2222+22222=24690。