逻辑表达式

在计算机中真假是黑白分明的。计算机的世界由 $0$ 和 $1$ 组成,$0$ 代表假,$1$ 代表真。

我们输入两个整数 $a$ 和 $b$,现在你需要判断 $a$ 是否大于 $b$、$a$ 是否小于或等于 $b$、$a$ 是否不等于 $b$。输出 $3$ 个整数,用空格隔开。对于每个询问,如果成立则输出 $1$,否则输出 $0$。

#include <iostream>
using namespace std;
int main() {
    int a, b;
    cin >> a >> b;
    cout << (a > b) << ' ' << (a <= b) << ' ' << (a != b);
    return 0;
}

可以发现,> 是大于,<= 是小于或等于,!= 是不等于。注意,如果要比较两个数是否相等, 使用的是 == 而不是 =,因为一个等号是赋值的意思。

  • 由这些关系运算符组成的不是 $0$ 就是 $1$ 的表达式被称为关系表达式
  • 我们用 $1$ 来代表真(成立),用 $0$ 来代表假(不成立)。在关系运算符左右两边放表达式(数字或者变量等),就会计算这两边的关系,返回 $1$ 或者 $0$。
  • 需要注意的是,如果关系表达式和算数表达式符号(如 +-*/%)一起使用,需要注意优先级问题。我们将在下文统一整理绝大多数各位目前可能用到的运算符的优先级。

现在提出上面问题的升级版:请你判断 $a$ 是否大于等于 $b$ 并且 $a$ 不等于 $0$,$a$ 是否小于 $b$ 或者 $b$ 是否等于 $1$(注意这一共十两个问题)。输出 $2$ 个整数,用空格隔开。

  • 注意到,现在有「并且」和「或者」这两个我们无法处理的关系。
  • 此时需要引入逻辑运算符。我们令 && 表示「并且」,|| 表示「或者」,注意这里是两个同样的 &|,单个的尽管在一些时候也可以运行,但它表示的含义完全不同,我们将在后面「位运算」一章讲到。

这样一来,上面的问题也可以被解决了。

#include <iostream>
using namespace std;
int main() {
    int a, b;
    cin >> a >> b;
    cout << (a >= b && a != 0) << ' ' << (a < b || b == 1) << endl;
    return 0;
}

如果此时向程序输入 2 2,那么获得的输出将是 1 0,因为 $a \ge b$,$a \not< b$ 而且 $b \ne 1$。

接下来从优先级高到低整理了常用运算符的优先级,高优先级先进行运算,相同优先级从左到右按顺序运算,请务必熟悉。

-(负号)*/%+-(加减运算)<><=>===!=&&` `

分支语句

if

洛谷 P5712

对于这道题目,要写出一个正确的英语句子。根据输入数据不同程序要做出不同的表现——如果输入不是 $0$ 或 $1$,就多输出一个 $\texttt{s}$。代码如下:

#include <iostream>
using namespace std;
int main() {
    int x;
    cin >> x;
    cout << "Today, I ate " << x << " apple";
    if (x != 0 && x != 1) {
        cout << "s";
    }
    cout << "." << endl;
    return 0;
}

在这个程序里,出现了一个我们从未见过的语句—— if。一般地,if 有如下格式:

if (成立条件的表达式) {
    当条件成立时需要执行的语句;
}

这里的「成立条件表达式」一般是指上面介绍过的关系表达式或者逻辑表达式——如果表达式是 $1$,或者只要不是 $0$,条件都会成立;如果是 $0$,条件就不成立了。

正如其在英文中的意思一样,if 表示「如果」。如果括号中的条件成立,程序将执行大括号 { } 中的内容;如果不成立则不执行。

因此,上面代码的流程是这样的:

  • 首先输入 $x$ ,知道吃了几个苹果。然后输出 $\texttt{Today, I ate } x \texttt{ apple}$,因为无论 $x$ 是多少,都要输出这样的句子。
  • 然后,当 $x$ 既不是 $0$,也不是 $1$ 时,说明要加上表示复数的 $\texttt{s}$。这就是 if 语句的作用。

else

洛谷 P5713

分析题目后可以发现,我们可以很容易地列出两种方式下分别消耗的时间——本地上传需要花费 $5n$ 分钟的时间, 而上传洛谷需要花费 $11+3n$ 分钟时间。如果前者小于后者,则选择在本地配置,否则选择洛谷上传。代码如下:

#include <iostream>
using namespace std;
int main() {
    int n;
    cin >> n;
    if (5 * n < 11 + 3 * n) {
        cout << "Local" << endl;
    }
    else {
        cout << "Luogu" << endl;
    }
    return 0;
}

注意到,这份代码中又多出来了一个 else 语句。如果有 else,前面一定有至少一个 if 。用法如下:

if (成立条件的表达式) {
    当条件成立时需要执行的语句;
}
else {
    当条件不成立时需要执行的语句;
}

正如 else 其意「否则」。这里是 if 语句的另外一种用法,配合上 else,就可以在条件成立的情况下做什么事情,否则,当条件不成立时做另外的一些事情。这里给出上面代码的流程图:

st=>start: 输入 n
cond=>condition: 本地时间更少?
op1=>operation: 输出 ”Local“
op2=>operation: 输出 “Luogu"
e=>end: 结束

st->cond
cond(yes)->op1->e
cond(no)->op2->e

特别地,如果需要执行的只有一条语句(也就是只有结尾的一个分号),那么大括号可以不要(甚至换行也可以不要),而空格和换行也都不是 C++ 的硬性要求。甚至,判断语句也可以不换行,上面的代码哪怕写成 if (5 * n < 11 + 3 * n) cout << "Local" << endl; else cout << "Luogu" << endl; 也是可以被运行的。

但如果取消所有空格和换行,代码的可读性将会大幅降低,我们不推荐取消许多换行与空格。

缩进与代码块

  • 在接触 if 语句时,写出来的代码开始有了「层次感」——上面代码中 if 语句后大括号内的语句相比于其他语句要往右移动了一点,这就是缩进
  • 我们通常使用 $4$ 个空格作为每个层级的缩进,这样可以一目了然地知道哪些语句是条件成立时才执行的。
  • 使用大括号 { } 括起来的语句称为代码块,代码块里面的代码相比于外面应当有统一的缩进。
  • 开头大括号可以像例子中给出的那样不换行,也可以另起一行,这取决于个人习惯。
  • 总之,写程序应当有良好的代码规范,比如换行、空格、缩进等,这也是为了使代码可读性强,更容易理解。

至此,你已经可以完成简单的条件判断了,这在以后将是相当常用的,请多加练习并尽量熟练。

最后修改:2024 年 02 月 02 日
如果觉得我的文章对你有用,请随意赞赏