1. 分支结构
1.1 单分支控制
if(条件){ 语句块1; }
如果条件成立,则执行语句块1,否则直接执行后继语句,语句块1被忽略,执行后继语句。
例3.1:输入两个数m和n,如果m<n,则交换两个数。
#include<iostream>using namespace std;int main(){int m,n;cin>>m>>n;if(m<n){int t=m;m=n;n=t;}cout<<"After if statement"<<endl;}
- 第7行为条件判断,如果m<n,则执行第9-11行,交换m和n的值。这个交换操作是C++中的基本操作;如果条件不成立,则跳过第8-12行,直接执行第13行。
- 第7行的右小括号右侧不能加分号,因为语句未结束。如果添加了分号,表示条件成立时执行空语句(单个分号表示空语句),第8-12行与第7行的if语句就没有任何关联性了。
- if语句后面只能接一条语句或一个语句块,如果需要执行多条语句,就用大括号将多条语句封装成语句块。初学者如果分不清什么时候加大括号,可以在任何时候都加大括号,这样语法上总是正确的。
- 真正的程序员必须保证代码具有良好的缩进,这里的if,以及后面将要提及的else,或循环语句,其关联的语句块都要保持缩进状态,这样可以非常快速的了解程序的层次关系。
1.2 双分支控制
如果条件成立,则执行语句块1,否则执行语句块2,二者必然有一项要被执行。if(条件){ 语句块1; }else{ 语句块2; }
else后面不写条件,但是具有隐含条件,即if的条件不成立。
例3.2:输入一个整数m,判断m的奇偶性。
#include<iostream>using namespace std;int main(){int m;cin>>m;if(m%2==0)cout<<"偶数"<<endl;else{cout<<"奇数"<<endl;}}
- 这里if和else接的语句都是单条语句,可以像第8行那样不加大括号,也可以像第11行那样增加大括号。
根据整型和布尔型之间的对应关系,以上程序也可以改写为:
#include<iostream>using namespace std;int main(){int m;cin>>m;if(m%2)cout<<"奇数"<<endl;elsecout<<"偶数"<<endl;}
进一步可以改写为问号表达式:条件?条件成立语句:条件不成立语句。首先进行条件判断,条件成立时执行冒号前的语句,否则执行冒号后的语句。这是C/C++中的三目运算符,极大简化了双分支结构的书写。
#include<iostream>using namespace std;int main(){int m;cin>>m;cout<<(m%2?"奇数":"偶数")<<endl;}
1.3 多分支控制
if(条件1){ 语句块1; }else if(条件2){ 语句块2; }else{ 语句块3; }
如果条件1成立,则执行语句块1,否则执行条件2的判断,如果条件2成立,执行语句块2,否则执行语句块3。必然有一个分支要被执行。
- else具有隐含条件,第3行的else表示条件1不成立,第5行的else表示条件1和条件2都不成立。因此不要在条件2中去判断条件1不成立,因为一旦执行到第4-6行,表示条件1肯定是不成立的,不需要判断。
- C/C++提供switch结构进行多分支,但是其执行效率与else if的多分支相同,不建议使用switch。
例3.3:编写一个程序,根据用户输入的期末考试成绩,输出相应的成绩评定信息。成绩大于等于90分输出“优”;成绩大于等于80分小于90分输出“良”;成绩大于等于60分小于80分输出“中”;成绩小于60分输出“差”。
#include<iostream>using namespace std;int main(){int score;cin>>score;int grade=score/10;if(grade>=9)cout<<"优秀"<<endl;else if(grade==8)cout<<"良好"<<endl;else if(7==grade)cout<<"一般"<<endl;else if(6==grade)cout<<"及格"<<endl;elsecout<<"不及格"<<endl;}
- 这里用到了整除特性,将百分制转换为10个区间,然后用多分支划分为5个区域。
- 第10行的
==如果误写为=,则程序流程为先将grade赋值为8,然后判断grade的布尔值。因为8为非零数,总是代表true,所以全部小于90的分数都会被输出良好。因此要特别注意==和=的区别。 当判断变量和常量是否相等时,建议把常量写在左侧,如果
==被误写为=,程序编译时会报错,因为常量不能被赋值。如第12行和第14行所示。1.4 分支嵌套
if(条件1){if(条件2){ 语句块2; }else{ 语句块3; }}else{ 语句块4; }
每个else 部分总是与它前面最近的那个缺少对应的 else 部分的 if 语句配对。
- 建议使用大括号避免二义性。
else具有隐含条件,第3行的else表示条件1不成立,第5行的else表示条件1和条件2都不成立。因此不要在条件2中去判断条件1不成立,因为一旦执行到第4-6行,表示条件1肯定是不成立的,不需要判断。
例3.4:将例3.3改写为分支嵌套结构。
#include<iostream>using namespace std;int main(){int score;cin>>score;if(score>=60){if(score<70)cout<<"及格"<<endl;else if(score<80)cout<<"一般"<<endl;else if(score<90)cout<<"良好"<<endl;elsecout<<"优秀"<<endl;}elsecout<<"不及格"<<endl;}
- 以第11行为例,不要将其写成
else if(score>=70 && score<80),这里的else代表的含义就是score>=70,不需要重复表达。2. 分支程序优化
程序设计是一种思维训练,每个程序都尽量的进行优化,这样可以锻炼思维,让程序达到最优。以两个样例探讨分支程序的优化。2.1 三天打鱼两天晒网
例3.5:中国有句俗语叫“三天打鱼两天晒网”。假设某人从某天起,开始三天打鱼两天晒网”,问这个人在以后的第N天中是”打鱼“还是晒网”?
【输入】
输入在一-行中给出1个不超过1000的正整数N。
【输出】
在一行中输出此人在第N天中是’Fishing” (打鱼”)还是“Drying” (晒网”),并且输出”on day N”。
【问题分析】第1-3天打鱼,第4-5天晒网,然后不断循环这个过程。这种数据的周期性最适合用取模运算进行解决。因此有了第一个解决方案:
【样例输入1】103#include<iostream>using namespace std;int main(){int day;cin>>day;if (day%5==1||day%5==2||day%5==3)cout<<"Fishing on day "<<day<<endl;elsecout<<"Drying on day "<<day<<endl;return 0;}
【样例输出1】
Fishing on day 103
【样例输入2】
34
【样例输出2】
Drying on day 34
考虑晒网的天数少,可以书写上减少一个条件,因此第7-10行可以改写为:
连续数字可以用范围表示,但是0和4在这个范围的两侧,不好归结。这时就可以考虑数学变换。第7-10行可以改写为:if (day%5==4||day%5==0)cout<<"Drying on day "<<day<<endl;elsecout<<"Fishing on day "<<day<<endl;
最后,还可以用问号表达式进行书写优化。if ((day-1)%5<3)cout<<"Fishing on day "<<day<<endl;elsecout<<"Drying on day "<<day<<endl;
cout<<((day-1)%5<3?"Fishing":"Drying")<<" on day "<<day<<endl;
2.2 虫子吃苹果
例3.6:你买了一箱n个苹果,很不幸的是买完时箱子里混进了一条虫子。虫子每x小时能吃掉一个苹果假设虫子在吃完一个苹果之前不会吃另 一个,那么经过y小时你还有多少个完整的苹果?
【输入】
输入仅一行,包括n, x和y (均为整数)
【输出】
输出仅一行,剩下的苹果个数
【样例输入1】10 4 9#include<iostream>using namespace std;int main(){int n,x,y;cin>>n>>x>>y;if (y%x==0)cout<<(n-y/x)<<endl;elsecout<<(n-y/x-1)<<endl;return 0;}
【样例输出1】
7
程序思想非常简单,如果y是x的倍数,则直接得到结果,否则需要多减一天。这里实际上是一种向上取整的方法,可以通过数学进行优化。因为x和y都是整数,所以最小的差距是1。如果在y的基础上增加x-1,那么只要有余数,被吃掉苹果的数量就会加1,如果正好整除,x-1会被整除操作自动舍弃。以下代码优化后去掉了分支操作。
C/C++中提供了ceil函数进行向上取整。书写上比数学方法麻烦,但是更容易理解。#include<iostream>using namespace std;int main(){int n,x,y;cin>>n>>x>>y;cout<<(n-(y+x-1)/x)<<endl;return 0;}
总而言之,可以通过语法、数学方法或库函数对程序进行优化。#include<iostream>#include<cmath> //支持ceil函数的定义using namespace std;int main(){int n,x,y;cin>>n>>x>>y;cout<<(n-ceil(y/(float)x))<<endl; //通过强制类型转换,把整除改为浮点数除法return 0;}
