跳转到内容

条件判断

到目前为止,我们写的程序结构都非常简单,都是从上往下,顺序执行的,然而在生活中我们还会经常遇到这样一种情况,需要根据各种不同条件来做出判断并采取不同行动,也就是我们经常所说的「决策」。

最简单的,早上去上学,我们需要决定用什么交通工具去上学?是走路去,还是坐公交车去,或者爸爸妈妈开车送去呢?我们判断的条件可能是:如果今天下雨,爸爸妈妈开车送我去;如果不下雨,那就坐公交车去。

这种根据条件判断来执行的情况在编程中我们就叫做 条件分支,往往能够用 如果 ... 那么 去描述的问题,都可以用条件分支去实现。

分支结构

下面是一个条件分支结构的一个简单流程图。

流程图,又称程序框图是表示算法、工作流或流程的一种框图表示,它以不同类型的框代表不同种类的步骤,每两个步骤之间则以箭头连接。这种表示方法便于说明解决已知问题的方法。我们在后面会有专门的章节讲到流程图。

这里的菱形框架代表条件判断(这里有分支);长方形框代表普通的逻辑步骤;箭头代表步骤执行的方向。

  • 当条件满足(True)时,走执行逻辑代码 1 这条路径;
  • 当条件不满足(False)时,走执行逻辑代码 2 这条路径。

来看一非常简单的例子:

#include <iostream>
using namespace std;
int main() {
int score;
cin >> score;
if (score >= 60) {
cout << "及格" << endl;
} else {
cout << "不及格" << endl;
}
return 0;
}

运行程序时,会提示你输入一个成绩,如果输入的数字大于等于 60,则输出 “及格”,否则输出 “不及格”。

注意在 if 后面判断的条件,而在 else 后是指满足判断的条件之外所有的情况,因此后面不需要写任何条件判断了。

在这里,else 后的代码就是指的当成绩小于 60 分的时候才会执行的内容。

关系运算符

在 C++ 中,可以使用不同的关系运算符来比较两个值之间的关系。

常见的有下面 6 种关系运算符。

  1. 相等运算符(==),用于检查两个值是否相等
  2. 不等运算符(!=),用于检查两个值是否不相等
  3. 大于运算符(>),用于检查一个值是否大于另一个值。
  4. 小于运算符(<),用于检查一个值是否小于另一个值。
  5. 大于运算符(>=),用于检查一个值是否大于等于另一个值。
  6. 大于运算符(<=),用于检查一个值是否小于等于另一个值。

通过单独或组合使用这些运算符,可以编写逻辑清晰、准确的代码来实现所需要的功能。

逻辑运算符

在 C++ 中,可以通过逻辑运算符将两个或多个关系表达式连接成一个进行逻辑运算,并根据运算的结果来执行条件判断。

共有下面三种逻辑运算符:

  1. 逻辑与运算符(&&

    表示同时满足两个条件时结果才为真(true)。例如 A && B,只有当条件 A 和 条件 B 都为真时,结果才为真。

  2. 逻辑或运算符(||

    表示只要满足任意一个条件时结果就为真(true)。例如 A || B,只要条件 A 或条件 B 当中有一个为真时,结果就为真。

  3. 逻辑非运算符(!

    表示取反操作,将真变为假,假变为真。例如 !A,如果条件 A 的值为真,那结果就为假,如果条件 A 的值为假,那结果就为真。

运算符优先级

对于逻辑运算符,这三者的优先级为

! > && > ||

因此,下面两个表达式有完全不同的作用。

!(x > 5) // 表达式1
!x > 5 // 表达式2
x || y && z // 表达式3

第一个表达式是将取反运算符(!) 应用于表达式 x > 5;而第二个表达式是先对 x 取反,看取反的结果是否大于 5 。

需要特别注意的是表达式3:

x || y && z

根据逻辑运算符的优先级,该表达式是等同于下面的表达式:

x || (y && z)

另外,逻辑运算符的优先级是低于关系运算符的,这意味着当他们放在一起时,应该先计算关系表达式,再应用逻辑运算符。

因此,

a > 100 && a < 500 // 等同于 (a > 100) && (a < 500)
a > 100 || a < 500 // 等同于 (a > 100) || (a < 500)

在任何时候,使用括号都是一个不错的选择,因为它可以让程序更易读。

多分支条件判断

上面关于成绩的判断只有两个分支,要么及格,要么不及格。在实际应用中,很可能有多个分支出现,还是以成绩判断为例,现在我们不简单只区分及格与不及格了,而是需要根据成绩的分数会打一个等级,等级的判断如下:

  • 如果成绩大于 90 分,则评为 A
  • 如果成绩在 80 ~ 90 分,则评为 B
  • 如果成绩在 70 ~ 80 分,则评为 C
  • 如果成绩在 60 ~ 70 分,则评为 D
  • 如果成绩低于 60 分,则评为 E

针对这种多分支的情况,我们就需要用到 else if 进行多分支判断。多分支的条件判断代码结构为:

if 条件1:
// 满足条件1需要执行的代码
else if 条件2:
// 满足条件2需要执行的代码
else if 条件3:
// 满足条件3需要执行的代码
else:
// 所有其它的情况需要执行的代码

应用多分支条件判断完成对成绩进行等级评定,代码如下:

#include <iostream>
using namespace std;
int main() {
int score;
cin >> score;
if (score >= 90) {
cout << "A" << endl;
} else if (score >= 80 && score < 90) {
cout << "B" << endl;
} else if (score >= 70 && score < 80) {
cout << "C" << endl;
} else if (score >= 60 && score < 70) {
cout << "D" << endl;
} else {
cout << "E" << endl;
}
return 0;
}

实际上,在第一个条件 score >= 90 后面的条件判断,就已经有一个默认的条件了,这个条件就是 score 是小于 90 的。例如,在第一个条件之后,如果遇到 score >= 80 ,其实相当于 score >= 80 && score < 90 了。

另外,在 C++ 中,如果条件判断内的执行语句只有一条,可以省略花括号,经过简化后的代码如下:

#include <iostream>
using namespace std;
int main() {
int score;
cin >> score;
if (score >= 90) cout << "A" << endl;
else if (score >= 80) cout << "B" << endl;
else if (score >= 70) cout << "C" << endl;
else if (score >= 60) cout << "D" << endl;
else cout << "E" << endl;
return 0;
}

switch 条件语句

当我们需要根据表达式的值来选择不同的执行路径时,可以使用 switch 条件语句。switch语句根据表达式的值与一系列 case 标签进行比较,并执行与匹配的 case 标签关联的代码块。

下面通过一个简单的代码示例来说明 switch 条件判断的使用。

根据输入的星期数(用 1 ~ 7 来表示),输出对应车辆限行的尾号。

#include <iostream>
using namespace std;
int main() {
int day; // 输入数字 1 - 7 的任意数
cin >> day;
switch (day) {
case 1: // 代表星期一
cout << "尾号 1、6 限行 " << endl;
break;
case 2: // 代表星期二
cout << "尾号 2、7 限行 " << endl;
break;
case 3: // 代表星期三
cout << "尾号 3、8 限行 " << endl;
break;
case 4: // 代表星期四
cout << "尾号 4、9 限行 " << endl;
break;
case 5: // 代表星期五
cout << "尾号 5、0 限行 " << endl;
break;
default:
cout << "不限行" << endl;
break;
}
return 0;
}

需要注意的是,最后的 default 标签一定要写,当表达式的值与任何一个 case 标签都不匹配时,程序会执行 default 标签下的代码块。另外,尽管 default 不定要放在 switch 语句的最后,但为了逻辑更加清晰,通常建议将其放在最后。

练习: 奇偶数判断

题目描述:

输入一个正整数,判断该数是奇数还是偶数,如果是偶数,输出 “Y”,如果不是偶数,输出 “N”。

输入输出样例:

输入1

4

输出1

Y

输入2

7

输出2

N

实现代码:

#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
if (n % 2 == 0) cout << n << "Y" << endl;
else cout << n << "N" << endl;
return 0;
}

练习: FizzBuzz

题目描述

输入一个正整数,如果该数是 3 的倍数,打印出 “Fizz”;如果是 5 的倍数,则打印出 “Buzz”;如果这个数既是 3 的倍数又是 5 的倍数,则打印出 “FizzBuzz”,其它情况则直接把这个数字打印出来。

输入输出样例

输入1

6

输出1

Fizz

输入2

10

输出2

Buzz

输入3

15

输出3

FizzBuzz

实现代码:

#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
if (n % 3 == 0 && n % 5 == 0) {
cout << "FizzBuzz" << endl;
} else if (n % 3 == 0) {
cout << "Fizz" << endl;
} else if (n % 5 == 0) {
cout << "Buzz" << endl;
} else {
cout << n << endl;
}
return 0;
}

FizzBuzz 这个任务,根据题目的描述顺序,很多人很容易写出下面的问题代码:

#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
if (n % 3 == 0) {
cout << "Fizz" << endl;
} else if (n % 5 == 0) {
cout << "Buzz" << endl;
} else if (n % 3 == 0 && n % 5 == 0) {
cout << "FizzBuzz" << endl;
} else {
cout << n << endl;
}
return 0;
}

输入 3 的倍数,或 5 的倍数,程序运行一切正常。但当输入一个既是 3 的倍数,又是 5 的倍数时(例如 15),程序运行结果就有问题了,打印出了 Fizz,实际上应该是 FizzBuzz,这是因为当进入第一个条件判断 if number % 3 == 0 时,条件就满足了(15 确实是 3 的倍数),相当于就被拦截了,根本就不会进入到下面的其它几个条件判断了。

注意,在写多分支条件判断的时候,越严格的条件应该放在越前面

当然,是不是不把严格的条件放在最前面就不能解决了?也不是。根据题意可知,当我们在说是 3 的倍数时,其实有一个隐含条件,这个数不是 5 的倍数,否则的话这个数就既是 3 的倍数又是 5 的倍数了。

因此,我们可以把这个隐含的条件写出来,问题就没有了,代码如下:

#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
if (n % 3 == 0 && n % 5 != 0) { //隐含条件补充上
cout << "Fizz" << endl;
} else if (n % 5 == 0 && n % 3 != 0) { //隐含条件补充上
cout << "Buzz" << endl;
} else if (n % 3 == 0 && n % 5 == 0) {
cout << "FizzBuzz" << endl;
} else {
cout << n << endl;
}
return 0;
}

练习: 计算薪水

题目描述

一个公司每月的薪水是由两部分组成:基础工资 + 奖金,奖金的的计算规则如下:

  • 如果服务年限在 5 年以内,奖金是 10%
  • 如果服务年限在 5 ~ 7 年,奖金是 15%
  • 如果服务年限在 7 ~ 10 年,奖金是 20%
  • 如果服务年限在 10 年以上,奖金是 25%

输入描述

输入为一行,包括两个浮点数

  • 一个保留两位小数的浮点数,代表当前基础工资
  • 一个整数,代表服务年限

输出描述

一个保留两位小数的浮点数,代表最终计算出的每月薪水

输入输出样例

输入数据

5500.00 10

输出数据

6875.00

实现代码

#include <iostream>
using namespace std;
int main() {
float b; // 基础工资
int y; // 服务年限
cin >> b >> y;
if (y >= 10) b = b * (1 + 0.25);
else if (y >= 7) b = b * (1 + 0.2);
else if (y >= 5) b = b * (1 + 0.15);
else b = b * ( 1 + 0.1);
printf("%.2f", b);
return 0;
}

练习: 闰年判断

题目描述

输入一个年份,判断该年份是闰年还是平年。

输入输出样例

输入1

2000

输出1

2000 是闰年

输入2

2011

输出2

2011 是平年

输入3

2020

输出3

2020 是闰年

题目解析

为了完成本任务,首先需要知道如何去判断闰年和平年。查阅资料可知道下面一些关于闰年的基本常识。

我们日常说每年有 365 天,实际这个 365 天并不准确,这是由于地球公转一周为365日5时48分46秒(或365.25日),与一年(365 天)相差5时48分46秒。这样每过四年就会多一天,因而被四整除的非世纪年是闰年,但这样每过四百年又多出一天。所以后来规定世纪年只有能被四百整除的才是闰年。

闰年(Leap Year) 就是为了弥补因人为历法规定造成的年度天数与地球实际公转周期的时间差而设立的。

下面这张图,源自 维基百科(重新做了绘制),可以很好的用于闰年的判断。

先观察上面的闰年判断流程图,发现只有两条路径可以判断为闰年,我们可以总结出如下的规律:

  1. 能被 400 整除的年份是闰年
  2. 能被 4 整除,但不能被 100 整除的年龄,是闰年
  3. 其余都是平年

再根据这个规律来完成程序,代码如下:

实现代码

#include <iostream>
using namespace std;
int main() {
int year;
cin >> year;
// 闰年判断逻辑
if (year % 400 == 0 || (year % 4 == 0 and year % 100 != 0)) {
cout << year << "是闰年" << endl;
} else {
cout << year << "是平年" << endl;
}
return 0;
}

小结

总之,条件判断(分支结构)是一种用于根据给定条件选择不同执行路径的结构,也是程序设计中的三大基本流程结构之一(除条件分支结构外,还有顺序结构和循环结构),通过合理运用条件判断,我们可以实现更加灵活的程序控制流程。