跳转至

循環

有時,我們需要做一件事很多遍,為了不寫過多重複的代碼,我們需要循環。

有時,循環的次數不是一個常量,那麼我們無法將代碼重複多遍,必須使用循環。

for 語句

以下是 for 語句的結構:

1
2
3
for (初始化; 判斷條件; 更新) {
  循環體;
}

執行順序:

e.g. 讀入 n 個數:

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

for 語句的三個部分中,任何一個部分都可以省略。其中,若省略了判斷條件,相當於判斷條件永遠為真。

while 語句

以下是 while 語句的結構:

1
2
3
while (判斷條件) {
  循環體;
}

執行順序:

e.g. 驗證 3x+1 猜想:

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

do...while 語句

以下是 do...while 語句的結構:

1
2
3
do {
  循環體;
} while (判斷條件);

執行順序:

與 while 語句的區別在於,do...while 語句是先執行循環體再進行判斷的。

e.g. 枚舉排列:

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

三種語句的聯繫

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// for 語句

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

// while 語句

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

在 statement4 中沒有 continue 語句(見下文)的時候是等價的,但是下面一種方法很少用到。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// while 語句

statement1;
while (statement2) {
  statement1;
}

// do...while 語句

do {
  statement1;
} while (statement2);

在 statement1 中沒有 continue 語句的時候這兩種方式也也是等價的。

1
2
3
4
5
6
7
while (1) {
  // do something...
}

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

這兩種方式都是永遠循環下去。(可以使用 break(見下文)退出。)

可以看出,三種語句可以彼此代替,但一般來説,語句的選用遵守以下原則:

  1. 循環過程中有個固定的增加步驟(最常見的是枚舉)時,使用 for 語句;
  2. 只確定循環的終止條件時,使用 while 語句;
  3. 使用 while 語句時,若要先執行循環體再進行判斷,使用 do...while 語句。一般很少用到,常用場景是用户輸入。

break 與 continue 語句

break 語句的作用是退出循環。

continue 語句的作用是跳過循環體的餘下部分。下面以 continue 語句在 do...while 語句中的使用為例:

1
2
3
4
5
6
do {
  // do something...
  continue;  // 等價於 goto END;
// do something...
END:;
} while (statement);

break 與 continue 語句均可在三種循環語句的循環體中使用。

一般來説,break 與 continue 語句用於讓代碼的邏輯更加清晰,例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 邏輯較為不清晰,大括號層次複雜

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...
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 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...
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 語句重複,順序不自然

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

// 沒有重複語句,順序自然

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