跳到主要内容

分支与循环结构


第一部分!

一个程序默认是按照代码的顺序执行下来的,有时我们需要选择性的执行某些语句,这时候就需要分支的功能来实现。选择合适的分支语句可以提高程序的效率。

if 语句

基本 if 语句

以下是基本 if 语句的结构。

if (条件) {
主体;
}

if 语句通过对条件进行求值,若结果为真(非 0),执行语句,否则不执行。

如果主体中只有单个语句的话,花括号可以省略。

if...else 语句

if (条件) {
主体1;
} else {
主体2;
}

if...else 语句和 if 语句类似,else 不需要再写条件。当 if 语句的条件满足时会执行 if 里的语句,if 语句的条件不满足时会执行 else 里的语句。同样,当主体只有一条语句时,可以省略花括号。

else if 语句

if (条件1) {
主体1;
} else if (条件2) {
主体2;
} else if (条件3) {
主体3;
} else {
主体4;
}

else if 语句是 if 和 else 的组合,对多个条件进行判断并选择不同的语句分支。在最后一条的 else 语句不需要再写条件。例如,若条件 1 为真,执行主体 1,条件 3 为真而条件 1 和条件 2 都为假,执行主体 3,所有的条件都为假才执行主体 4。

实际上,这一个语句相当于第一个 if 的 else 分句只有一个 if 语句,就将花括号省略之后放在一起了。如果条件相互之间是并列关系,这样写可以让代码的逻辑更清晰。

在逻辑上,大约相当于这一段话:

解一元二次方程的时候,方程的根与判别式的关系:

  • 如果 (Δ<0\Delta<0) 方程无解;
  • 否则,如果 (Δ=0\Delta=0) 方程有两个相同的实数解;
  • 否则 方程有两个不相同的实数解;

switch 语句

switch (选择句) {
case 标签1:
主体1;
case 标签2:
主体2;
default:
主体3;
}

switch 语句执行时,先求出选择句的值,然后根据选择句的值选择相应的标签,从标签处开始执行。其中,选择句必须是一个整数类型表达式,而标签都必须是整数类型的常量。例如:

int i = 1;  // 这里的 i 的数据类型是整型 ,满足整数类型的表达式的要求

switch (i) {
case 1:
cout << "OI WIKI" << endl;
}
char i = 'A';

// 这里的 i 的数据类型是字符型 ,但 char
// 也是属于整数的类型,满足整数类型的表达式的要求
switch (i) {
case 'A':
cout << "OI WIKI" << endl;
}

switch 语句中还要根据需求加入 break 语句进行中断,否则在对应的 case 被选择之后接下来的所有 case 里的语句和 default 里的语句都会被运行。具体例子可看下面的示例。

char i = 'B';

switch (i) {
case 'A':
cout << "OI" << endl;
break;

case 'B':
cout << "WIKI" << endl;

default:
cout << "Hello World" << endl;
}

以上代码运行后输出的结果为 WIKIHello World,如果不想让下面分支的语句被运行就需要 break 了,具体例子可看下面的示例。

char i = 'B';

switch (i) {
case 'A':
cout << "OI" << endl;
break;

case 'B':
cout << "WIKI" << endl;
break;

default:
cout << "Hello World" << endl;
}

以上代码运行后输出的结果为 WIKI,因为 break 的存在,接下来的语句就不会继续被执行了。最后一个语句不需要 break,因为下面没有语句了。

处理入口编号不能重复,但可以颠倒。也就是说,入口编号的顺序不重要。各个 case(包括 default)的出现次序可任意。例如:

char i = 'B';

switch (i) {
case 'B':
cout << "WIKI" << endl;
break;

default:
cout << "Hello World" << endl;
break;

case 'A':
cout << "OI" << endl;
}

switch 的 case 分句中也可以选择性的加花括号。不过要注意的是,如果需要在 switch 语句中定义变量,花括号是必须要加的。例如:

char i = 'B';

switch (i) {
case 'A': {
int i = 1, j = 2;
cout << "OI" << endl;
ans = i + j;
break;
}

case 'B': {
int qwq = 3;
cout << "WIKI" << endl;
ans = qwq * qwq;
break;
}

default: {
cout << "Hello World" << endl;
}
}
如何理解 switch

在上文中,用了大量「case 分句」,「case 子句」等用语,实际上,在底层实现中,switch 相当于一组跳转语句。也因此,有 Duff's Device 这种奇技淫巧,希望了解的人可以自行学习。


第二部分!

有时,我们需要做一件事很多遍,为了不写过多重复的代码,我们需要循环。

有时,循环的次数不是一个常量,那么我们无法将代码重复多遍,必须使用循环。

for 语句

以下是 for 语句的结构:

for (初始化; 判断条件; 更新) {
循环体;
}

执行顺序:

e.g. 读入 n 个数:

for (int i = 1; i <= n; ++i) {
cin >> a[i];
}

for 语句的三个部分中,任何一个部分都可以省略。其中,若省略了判断条件,相当于判断条件永远为真。

while 语句

以下是 while 语句的结构:

while (判断条件) {
循环体;
}

执行顺序:

e.g. 验证 3x+1 猜想:

while (x > 1) {
if (x % 2 == 1) {
x = 3 * x + 1;
} else {
x = x / 2;
}
}

do...while 语句

以下是 do...while 语句的结构:

do {
循环体;
} while (判断条件);

执行顺序:

与 while 语句的区别在于,do...while 语句是先执行循环体再进行判断的。

e.g. 枚举排列:

do {
// do someting...
} while (next_permutation(a + 1, a + n + 1));

三种语句的联系

// for 语句

for (statement1; statement2; statement3) {
statement4;
}

// while 语句

statement1;
while (statement2) {
statement4;
statement3;
}

在 statement4 中没有 continue 语句(见下文)的时候是等价的,但是下面一种方法很少用到。

// while 语句

statement1;
while (statement2) {
statement1;
}

// do...while 语句

do {
statement1;
} while (statement2);

在 statement1 中没有 continue 语句的时候这两种方式也也是等价的。

while (1) {
// do something...
}

for (;;) {
// do something...
}

这两种方式都是永远循环下去。(可以使用 break(见下文)退出。)

可以看出,三种语句可以彼此代替,但一般来说,语句的选用遵守以下原则:

  1. 循环过程中有个固定的增加步骤(最常见的是枚举)时,使用 for 语句;
  2. 只确定循环的终止条件时,使用 while 语句;
  3. 使用 while 语句时,若要先执行循环体再进行判断,使用 do...while 语句。一般很少用到,常用场景是用户输入。

break 与 continue 语句

break 语句的作用是退出循环。

continue 语句的作用是跳过循环体的余下部分。下面以 continue 语句在 do...while 语句中的使用为例:

do {
// do something...
continue; // 等价于 goto END;
// do something...
END:;
} while (statement);

break 与 continue 语句均可在三种循环语句的循环体中使用。

一般来说,break 与 continue 语句用于让代码的逻辑更加清晰,例如:

// 逻辑较为不清晰,大括号层次复杂

for (int i = 1; i <= n; ++i) {
if (i != x) {
for (int j = 1; j <= n; ++j) {
if (j != x) {
// do something...
}
}
}
}

// 逻辑更加清晰,大括号层次简单明了

for (int i = 1; i <= n; ++i) {
if (i == x) continue;
for (int j = 1; j <= n; ++j) {
if (j == x) continue;
// do something...
}
}
// for 语句判断条件复杂,没有体现「枚举」的本质

for (int i = l; i <= r && i % 10 != 0; ++i) {
// do something...
}

// for 语句用于枚举,break 用于「到何时为止」

for (int i = l; i <= r; ++i) {
if (i % 10 == 0) break;
// do something...
}
// 语句重复,顺序不自然

statement1;
while (statement3) {
statement2;
statement1;
}

// 没有重复语句,顺序自然

while (1) {
statement1;
if (!statement3) break;
statement2;
}