460 likes | 563 Views
第三章 程序的控制结构. 教学目标. (1) 理解控制语句的作用和分类,掌握相关语句的使用方法; (2) 了解使用伪代码或流程图描述算法的方法。. 基本内容. 3.1 基本控制结构 3.2 选择结构 3.3 循环结构 . 3.1 基本控制结构. 三大基本程序结构 : 顺序结构 :程序是按程序语句或模块在执行流中的顺序逐个执行。 选择结构 :程序是按设定的条件实现程序执行流的多路分支。 循环结构 :程序是按给定的条件重复地执行指定的程序段或模块。 结论:理论上已经证明,用以上三种基本程序结构的组合可以实现任何复杂的算法。. 顺序结构 选择结构.
E N D
教学目标 • (1) 理解控制语句的作用和分类,掌握相关语句的使用方法; • (2) 了解使用伪代码或流程图描述算法的方法。
基本内容 • 3.1 基本控制结构 • 3.2 选择结构 • 3.3 循环结构
3.1 基本控制结构 • 三大基本程序结构: • 顺序结构:程序是按程序语句或模块在执行流中的顺序逐个执行。 • 选择结构:程序是按设定的条件实现程序执行流的多路分支。 • 循环结构:程序是按给定的条件重复地执行指定的程序段或模块。 • 结论:理论上已经证明,用以上三种基本程序结构的组合可以实现任何复杂的算法。
顺序结构 选择结构 循环结构 三大基本结构示意图 (当型循环) 不成立 模块(语句)A 条件 成立 模块(语句)B 程序模块 (直到型循环) 成立 不成立 条件 程序模块 程序模块1 程序模块2 成立 条件 不成立
顺序结构的实现 r = p; p = q; q = r;
例 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; }
3.2 选择结构 • C/C++语言中实现选择结构的语句形式主要有两种: • if语句 • switch语句
一路分支: if (表达式) 语句序列 两路分支: if (表达式) 语句序列1 else 语句序列2 1. if语句 条件? 不成立 成立 成立 不成立 条件? 语句序列 语句序列 1 语句序列 2 语句序列可以是一个语句,也可以是用花括号括起来的复合语句结构
例 3-2:判断成绩是否及格 #include <iostream> using namespace std; int main() { int i; cout<<"请输入(百分制)分数:"; cin>>i; if(i>=60) cout<<"及格"<<endl; else cout<<"不及格"<<endl; return 0; }
例 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; }
多路(开关)选择语句 : switch (表达式) { case 数值1: 语句序列1; case 数值2: 语句序列2; case 数值3: 语句序列3; ... default: 语句序列n; } 2. switch语句
实现真正的多路选择 • 在每一个case模块的最后加上一个break语句
例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; }
3.3 循环结构 • C/C++语言中实现循环结构的语句形式主要有三种: • while语句 • do-while语句 • for语句
当型循环 while (表达式) { 语句序列 } 直到型循环 do { 语句序列 } while (表达式); while语句 | do-while语句 循环体 循环体 不成立 条件? 语句序列 成立 成立 语句序列 条件? 不成立
例 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; }
例 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; }
for语句 • for语句用来实现计数循环: for (表达式1; 表达式2; 表达式3) { 语句1; 语句2; ... 语句n; }
例 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; }
例 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; }
九九乘法表输出 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.4 其他控制转移语句 • 3.4.1 switch语句(点击见前) • 3.4.2 转向语句 • break语句、continue语句、 goto语句 • 3.4.3 问号表达式 • 表达式1 ?表达式2 :表达式3
上机指导 • 3.5 运行错误 • 常见的编程错误主要分为两类: • (1) 编译、连接错误: • 当程序中有语法错误或函数调用出错时就会出现。可通过C++编译和连接程序来改正。 • (2) 运行错误: • 一种是逻辑错误, 即程序的实际运行结果和编程者对程序结果的期望不符; • 另一种仍是程序设计上的错误, 但是躲过了编译程序和连接程序的检查, 通常表现为突然死机、自行热启动或者输出信息混乱。
应用举例 • 例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; //计算奖金bonus if(serviceYears <= 7) bonus=10*serviceYears; else bonus=20*serviceYears; cout<<"请输入经纪人当月销售额:"; cin>>totalSale; //计算提成additionalBonus if(totalSale < 10000) additionalBonus=0; else if(totalSale < 50000) additionalBonus=totalSale*(0.03); else additionalBonus=totalSale*(0.05); //计算经纪人的月薪Salary Salary = baseSalary+ bonus+ additionalBonus; cout<<"该经纪人的月薪为:"<<Salary<<endl; return 0; }
应用举例 • 例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; }
应用举例 • 例3-10计算自然常数e的值
算 法 分 析 • 这是个级数计算问题,求n+1项累加和;用循环实现。循环终止的条件是 • 第n项可以写成 u = u / n,即 • 累加和放在e中,可以写成 e = e + u • 要设一个计数器n,每循环一次, n = n + 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; }
应用举例 • 例 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; }
应用举例 • 例 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,…
#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; }
应用举例 • 例3-15 鸡兔同笼 • 鸡和兔子关在一个笼子里,已知共有头36个,脚100个,求笼内关了多少只兔子和多少只鸡? • 分析:每只鸡有两只脚,每只兔子有四只脚,由题意得到如下方程: • 鸡的数目×2+兔子数目×4=100 • 鸡的数目+兔子数目=36
穷举法 • 对所有可能情况一一测试,从中找出符合条件的(一个或一组)解,或得出无解的结论。 • 算法如下: chicken=0; while(chicken<=36) { 尝试是否满足两个方程,如是则输出解chicken, rabbit 准备下一轮尝试 chicken++; }
#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; }
案例:谁打烂了玻璃? • 有四个小孩踢皮球,不小心打烂了玻璃,老师问是谁干的。 • A说:不是我 • B说:是C • C说:是D • D说:他胡说 现已知3个小孩说的是真话,一个小孩是假话。根据这些信息,编程找出打烂玻璃的孩子。 打烂玻璃者为:C • 教学设问 • 如何求解逻辑问题? • 如何根据案例的问题描述给出对应的数学模型? • 用什么样的控制结构能够从许多种可能性中找出其中的一种或多种正确的解? *更多案例见本书配套教材《C/C++语言程序设计案例教程 》罗建军等编著,清华大学出版社
设变量k表示打烂玻璃的孩子 A说:不是我B说:是CC说:是DD说:他胡说现已知3个人说的是真话,一个人是假话。 k!=1 k==3 k==4 k!=4 数学模型 ((k!=1)+(k==3)+(k==4)+(k!=4))==3
按照这4种状态假定,逐一测试4个人的话有几个为真,如果不满3句为真,就否定这一假定,换下一个状态来试按照这4种状态假定,逐一测试4个人的话有几个为真,如果不满3句为真,就否定这一假定,换下一个状态来试
#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; }
进一步思考 • 考虑更加一般的情况,即本案例出现没有解或有多个解,要为上面的程序增加什么机制,怎么修改程序? • 如果题目改为有3个小孩说假话,1个小孩说真话,则打烂玻璃的孩子又是谁?
结 束 语 学好程序设计语言的唯一途径是 你的编程能力与你在计算机上投入的时间成 上机练习 正比