第三章 程序的控制结构
-
Upload
kim-spears -
Category
Documents
-
view
81 -
download
2
description
Transcript of 第三章 程序的控制结构
第三章
程序的控制结构
3
教学目标
(1) 理解控制语句的作用和分类,掌握相关语句
的使用方法;
(2) 了解使用伪代码或流程图描述算法的方法。
4
基本内容
3.1 基本控制结构3.2 选择结构3.3 循环结构
5
3.1 基本控制结构三大基本程序结构 :
顺序结构:程序是按程序语句或模块在执行流中的顺序逐个执行。
选择结构:程序是按设定的条件实现程序执行流的多路分支。
循环结构:程序是按给定的条件重复地执行指定的程序段或模块。
结论:理论上已经证明,用以上三种基本程序结构的组合可以实现任何复杂的算法。
6
三大基本结构示意图
顺序结构
选择结构
循环结构
模块(语句) A
模块(语句) B
条件条件
程序模块 1程序模块 1
成立 不成立
程序模块 2程序模块 2
条件条件
程序模块程序模块
不成立
成立
(当型循环)
程序模块程序模块
成立
不成立
条件条件
(直到型循环)
7
顺序结构的实现
r = p;
p = q;
q = r;
8
例 3-1 交换两个变量的值#include <iostream>using namespace std;int main(){
int a=1, b=2;int tmp; // 定义一个整型变量作为中间交换之用cout << " 交换前: a= " << a << ", b= " << b << endl;tmp = a;a = b;b = tmp;cout << " 交换后: a= " << a << ", b= " << b << endl;return 0;
}
9
3.2 选择结构
C/C++ 语言中实现选择结构的语句形式主要有两种: if 语句
switch 语句
10
1. if 语句
一路分支: if (表达式)
语句序列
条件?条件?成立
不成立
语句序列语句序列
两路分支: if (表达式) 语句序列 1
else
语句序列 2
条件?条件?
语句序列 1语句序列 1
成立 不成立
语句序列 2语句序列 2
语句序列可以是一个语句,也可以是用花括号括起来的复合语句结构
11
例 3-2 :判断成绩是否及格
#include <iostream>using namespace std;int main(){
int i;cout<<" 请输入(百分制)分数: ";cin>>i;if(i>=60)
cout<<" 及格 "<<endl;else
cout<<" 不及格 "<<endl;return 0;
}
12
例 3-3 :求一元二次方程的根#include <iostream>#include <cmath>using namespace std;int main(){ double a, b, c, delta, p, q;
cout << " 请输入系数 a, b, c = ";cin >> a >> b >> c;if(( a==0 ) && ( b==0 ) && ( c==0 )) // 最极端情况
cout << " 方程的根可为任意值 " << endl;else if(( a==0 ) && (b != 0)) // 转换为一元一次方程情况
cout << "x1 = x2 = " << -c/b << endl;else // 一般情况{
delta = b*b-4*a*c;p = -b/(2*a);q = sqrt(fabs(delta))/(2*a);if(delta >= 0) // 实根情况
cout << "x1 = " << p+q << endl << "x2 = " << p-q << endl;else // 存在共轭复根情况{ cout << "x1 = " << p << " + " << q <<"i"<< endl;
cout << "x2 = " << p << " - " << q <<"i"<<endl;}
}return 0;
}
13
2. switch 语句
多路(开关)选择语句 : switch (表达式 )
{
case 数值 1: 语句序列 1; case 数值 2: 语句序列 2; case 数值 3: 语句序列 3;...
default: 语句序列 n; }
语句序列3
表达式的值等于?
数值1 其他
语句序列1
图3.6 swi tch语句
语句序列2 语句序列n
数值2 数值3
…
14
实现真正的多路选择
在每一个 case 模块的最后加上一个 break 语句
语句序列3
表达式的值等于?
数值1 其他
语句序列1
图3.7 与break语句连用的swi tch语句
语句序列2 语句序列n
数值2 数值3
…
15
例 3.2 百分制化为优秀、良好、中等、及格和不及格的五级制成绩
算法分析: 取一个百分成绩经过运算得到 5 级制成绩。构造什么样的表达式呢?
“百分成绩 /10 =” ? 共有 5 个分数档,选择分支大于 2 ,因此用多路开关语句 switch 。
计算结果应该是唯一的。转换后应从 switch中 break出来。
#include <iostream>using namespace std;int main(){ int grade;
cout<<" 请输入(百分制)分数: ";cin >>grade;switch (grade/10) // 根据转换值进行分支选择{case 10:case 9:
cout<<" 优秀 "<<endl;break;
case 8:cout<<" 良好 "<<endl;break;
case 7: cout<<" 中等 "<<endl;break;
case 6:cout<<" 及格 "<<endl;break;
default:cout<<" 不及格 "<<endl;
}return 0;
}
17
3.3 循环结构
C/C++ 语言中实现循环结构的语句形式主要有三种: while 语句
do-while语句
for 语句
18
while 语句 | do-while语句
当型循环 while (表达式) {
语句序列 }
直到型循环 do
{
语句序列 } while (表达式) ;
循环
体 循环
体
条件?条件?
语句序列语句序列
成立
不成立
语句序列语句序列
不成立
成立条件?条件?
19
例 3-4 :使用 while 语句计算 1+2+3+…+100
#include <iostream>using namespace std;int main(){
int i=1, sum=0; // 循环初始条件while(i<=100){
sum=sum+i; // 累加求和i++; // 改变循环条件
}cout << "1+2+3+…+100="<<sum<<endl;return 0;
}
20
例 3-5 :使用 do-while 语句计算 1+2+3+…+100
#include <iostream>using namespace std;int main(){
int i=1, sum=0; // 循环初始条件do{
sum=sum+i; // 累加求和i++; // 改变循环条件
}while(i<=100);cout << "1+2+3+…+100="<<sum<<endl;return 0;
}
21
for语句
for 语句用来实现计数循环 :
for ( 表达式 1; 表达式 2; 表达式 3)
{
语句 1 ; 语句 2 ;
... 语句 n ;}
表达式2
真
假
执行表达式1
图3.5 for语句
语句序列
执行表达式3
22
例 3-6 :使用 for 语句计算 1+2+3+…+100
#include <iostream>
using namespace std;
int main()
{
int sum=0;
for(int i=1; i<=100; i++) sum=sum+i; // 累加求和cout << "1+2+3+…+100="<<sum<<endl;
return 0;
}
23
例 3-7 :制作乘法表 --- 多重循环结构(循环的嵌套)
#include <iostream>using namespace std;int main(){
int i, j;for(i=1; i<10; i++){
for(j=1; j<=i; j++)cout << j <<"*"<< i <<"="<<i*j <<"\t";
cout << endl;}return 0;
}
24
九九乘法表输出
1*1=11*2=2 2*2=41*3=3 2*3=6 3*3=91*4=4 2*4=8 3*4=12 4*4=161*5=5 2*5=10 3*5=15 4*5=20 5*5=251*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=361*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=491*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=641*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
25
扩展阅读
3.4 其他控制转移语句3.4.1 switch语句(点击见前)
3.4.2 转向语句break 语句、 continue 语句、 goto 语句
3.4.3 问号表达式表达式 1 ?表达式 2 :表达式 3
26
上机指导
3.5 运行错误 常见的编程错误主要分为两类:
( 1 ) 编译、连接错误: 当程序中有语法错误或函数调用出错时就会出现。可通过C ++ 编译和连接程序来改正。
( 2 ) 运行错误: 一种是逻辑错误 , 即程序的实际运行结果和编程者对程序结果的期望不符 ;
另一种仍是程序设计上的错误 , 但是躲过了编译程序和连接程序的检查 , 通常表现为突然死机、自行热启动或者输出信息混乱。
27
应用举例 例 3-10 计算保险经纪人月薪 假定每一名保险经纪人的月工资都由三部分组成:
底薪+奖金+业务提成。 1 )奖金的颁发方法为:
如果经纪人已经在公司工作 7年以下(含 7年),奖金为每年 10 元; 如果经纪人已经在公司工作 7年以上,奖金为每年 20 元。
2 )业务提成的颁发方法为: 如果经纪人该月销售额在 9999 元以下(含 9999 元),没有提成; 如果经纪人该月销售额在 10000~ 49999 元之间,可得到 3%的提
成; 如果经纪人该月销售额超过 50000 元(含),可得到 5%提成。
编程要求:当用户按照屏幕提示分别输入经纪人的底薪、工龄以及当月销售额后,程序计算并输出经纪人的月薪。
#include <iostream>using namespace std;int main(){
//声明部分,定义程序中将用到的变量double baseSalary, bonus, totalSale, additionalBonus, Salary;int serviceYears;cout<<" 请输入底薪: ";cin>>baseSalary;cout<<" 请输入经纪人在公司的工作年数: ";cin>>serviceYears;// 计算奖金 bonusif(serviceYears <= 7)
bonus=10*serviceYears;else
bonus=20*serviceYears;cout<<" 请输入经纪人当月销售额: ";cin>>totalSale;// 计算提成 additionalBonusif(totalSale < 10000)
additionalBonus=0;else
if(totalSale < 50000)additionalBonus=totalSale*(0.03);
elseadditionalBonus=totalSale*(0.05);
// 计算经纪人的月薪 Salary Salary = baseSalary+ bonus+ additionalBonus;cout<<" 该经纪人的月薪为: "<<Salary<<endl;return 0;
}
29
应用举例 例 3-11 编写计算阶乘 n! 的程序。
n! = n×(n-1)×(n-2)×…×2×1#include <iostream>using namespace std;int main(){
int n; // 定义存放输入正整数值的变量int u = 1; // 定义存放乘法结果的变量 u并赋初值cout<<" 请输入任意正整数 : ";cin>>n;for (int i=1; i<=n; i++) u = u*i;
cout << n <<"! = " << u << endl;return 0;
}
30
应用举例 例 3-10 计算自然常数 e 的值
...!
1...
!2
1
!1
11
ne
算 法 分 析
这是个级数计算问题,求 n+1项累加和;用循环实现。循环终止的条件是
第 n项可以写成 u = u / n ,即
累加和放在 e 中,可以写成 e = e + u
要设一个计数器 n ,每循环一次, n = n + 1
610!
1 n
nnn )!*1(
1
!
1
// 例 3-12 :计算常数 e 的值#include <iostream>using namespace std; int main(){
double e = 1.0;int n= 0; double u = 1.0;do{
n ++;u = u/n;e = e+u;
}while(u>=1.0E-6);cout << "e = " << e << " ( n = " << n << " )" << endl;return 0;
}
33
应用举例 例 3-13 :求水仙花数
如果一个三位数的个位数、十位数和百位数的立方和等于该数自身,则称该数为水仙花数。编一程序求出所有的水仙花数。
153 = 1^3 + 5^3 + 3^3 370 = 3^3 + 7^3 + 0^3 371 = 3^3 + 7^3 + 1^3 407 = 4^3 + 0^3 + 7^3
算法分析用穷举法对 100~999 之间的每个数进行验证。
验证公式为: hdn= h^3 + d^3 + n^3
如何分解一个 3位数的百位、十位和个位?是关键!
百位 = n / 100 [ 整除 100 ,丢弃小数 ]
十位 = ( n / 10 )% 10 [ 整除 10 ,得百十位。再对 10 取余数,得十位数 ]
个位 = n % 10 [n对 10 取余数,得个位 ]
例: 371 h = 371/100 = 3 d = ( 371/10)%10 = 37 % 10 = 7 n = 371 % 10 = 1
#include <iostream>
using namespace std; int main(){
int n, i, j, k;for(n=100; n<=999; n=n+1){ i = n/100; // 取出 n 的百位数 j = (n/10)%10; // 取数 n 的十位数 k = n%10; // 取出 n 的个位数 if(n==i*i*i+j*j*j+k*k*k)
cout <<n<<" = "<<i<<"^3 + "<<j<<"^3 +"<<k<<"^3"<<endl;}return 0;
}
36
应用举例 例 3-14 :计算斐波那契数列
一对兔子从出生后第 3 个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如所有的兔子都不会死,求前 24 个月中每月的兔子数。 F1 = 1 (最初的一对兔子) F2 = 1 (第 2 个月,最初的一对兔子长成,但尚未生育)
F3 = 2 (最初的兔子开始生育) … Fn = Fn-1+Fn-2 (兔子数量的通项公式,即每月兔子数等于上
两个月兔子数之和) 从而形成了如下数列
1, 1, 2, 3, 5, 8, 13, 21, 34, 55,…
37
#include <iostream>using namespace std;int main(){
int f1=1;int f2=1;int i;for(i=1; i<=12; i++){
cout<<f1<<"\t"<<f2<<"\t";f1=f1+f2; // 赋值号左边的 f1 代表第 3 个数,是第 1、 2 个数之
和f2=f2+f1; // 赋值号左边的 f2 代表第 4 个数,是第 2、 3 个数之
和}cout<<endl;return 0;
}
38
应用举例 例 3-15 鸡兔同笼
鸡和兔子关在一个笼子里,已知共有头 36 个,脚 100个,求笼内关了多少只兔子和多少只鸡?
分析:每只鸡有两只脚,每只兔子有四只脚,由题意得到如下方程: 鸡的数目 ×2 +兔子数目 ×4= 100 鸡的数目+兔子数目= 36
39
穷举法
对所有可能情况一一测试,从中找出符合条件的(一个或一组)解,或得出无解的结论。
算法如下:chicken=0;
while(chicken<=36)
{
尝试是否满足两个方程,如是则输出解 chicken, rabbit
准备下一轮尝试 chicken++;
}
40
#include <iostream>using namespace std;int main(){
int rabbit=0;int chicken=0;while(chicken<=36){
if(((100-chicken*2)%4==0)&&((chicken+(100-chicken*2)/4)==36)){
rabbit=(100-chicken*2)/4;cout<<"鸡: "<<chicken<<" 兔: "<<rabbit<<endl;
}chicken++;
}return 0;
}
41
案例:谁打烂了玻璃? 有四个小孩踢皮球,不小心打烂了玻璃,老师问是谁干的。
A说:不是我 B说:是 C C说:是 D D说:他胡说
现已知 3 个小孩说的是真话,一个小孩是假话。根据这些信息,编程找出打烂玻璃的孩子。
• 教学设问• 如何求解逻辑问题?• 如何根据案例的问题描述给出对应的数学模型?• 用什么样的控制结构能够从许多种可能性中找出其中的一种或多种正确的解?
打烂玻璃者为: C
* 更多案例见本书配套教材《 C/C++语言程序设计案例教程 》罗建军等编著,清华大学出版社
A说:不是我
B说:是 C
C说:是 D
D说:他胡说
现已知 3个人说的是真话,一个人是假话。
数学模型
k!=1
k==3
k==4
k!=4
((k!=1)+(k==3)+(k==4)+(k!=4))==3
设变量 k 表示打烂玻璃的孩子
状态 \ 代号 A ( 1 ) B ( 2 ) C ( 3 ) D ( 4 ) 说真话人数
① 打烂玻璃 0 0 0 1
② 0 打烂玻璃 0 0 2
③ 0 0 打烂玻璃 0 3
④ 0 0 0 打烂玻璃 1
按照这 4 种状态假定,逐一测试 4 个人的话有几个为真,如果不满 3 句为真,就否定这一假定,换下一个状态来试
44
#include <iostream>using namespace std;int main(){
for(int k=1; k<=4; k++)if((k!=1)+(k==3)+(k==4)+(k!=4)==3)
cout<<" 打烂玻璃者为: "<<char(64+k)<<endl;return 0;
}
45
进一步思考
考虑更加一般的情况,即本案例出现没有解或有多个解,要为上面的程序增加什么机制,怎么修改程序?
如果题目改为有 3 个小孩说假话, 1 个小孩说真话,则打烂玻璃的孩子又是谁?
46
学好程序设计语言的唯一途径是
你的编程能力与你在计算机上投入的时间成
结 束 语