停不下来的循环,是因为条件永远不会变成假。漏掉最后一项的循环,是提前一轮就停了。两者最快的发现方法,都是手动追踪循环,每一轮一行。
本页为每一种情况各给一个完整例子、一个修正版本和一份简短的检查清单。这里的记法是简单易读的伪代码。你的试卷可能使用特定风格,请对照考纲确认适用的路线。
停不下来的循环长什么样?
看这个算法。它本意是每次减 3,倒数到零。
Num ← 10
WHILE Num <> 0
Num ← Num - 3
ENDWHILE
OUTPUT "Done"
追踪它,并每次写出条件的结果。
| 第几轮 | 开始时的 Num | Num <> 0 ? | 结束时的 Num |
|---|---|---|---|
| 1 | 10 | 真 | 7 |
| 2 | 7 | 真 | 4 |
| 3 | 4 | 真 | 1 |
| 4 | 1 | 真 | −2 |
| 5 | −2 | 真 | −5 |
Num 依次是 10、7、4、1、−2、−5,永远不会刚好等于 0。“不等于 0”这个测试一直为真,所以永远到不了 “Done”。
怎样修正?
把条件改成:当数值越过目标时就停止,而不只是刚好等于目标时才停。
Num ← 10
WHILE Num > 0
Num ← Num - 3
ENDWHILE
OUTPUT Num
追踪:10 → 7 → 4 → 1 → −2。第四轮之后 Num 是 −2,而 −2 > 0 为假,所以循环停止。输出是 −2。
值得养成的习惯:当数值以固定步长变化时,优先使用大于或小于的条件,除非你已经证明步长刚好会落在目标上。
漏掉最后一项的循环长什么样?
下面是一个有五个分数的数组(array),这个例子里索引从 1 数到 5。任务是把它们全部加起来。
Scores = [12, 7, 15, 9, 10]
Total ← 0
FOR i ← 1 TO 4
Total ← Total + Scores[i]
NEXT i
OUTPUT Total
| i | Scores[i] | 相加后的 Total |
|---|---|---|
| 1 | 12 | 12 |
| 2 | 7 | 19 |
| 3 | 15 | 34 |
| 4 | 9 | 43 |
输出是 43,但真正的总和是 12 + 7 + 15 + 9 + 10 = 53。循环在 4 停下,所以 Scores[5] = 10 从未被加上。差值 53 − 43 = 10 正好是漏掉的那一项,检查自己的答案时,这是个有用的线索。
怎样修正差一错误?
让循环的最后一个值等于数组的最后一个索引。
Total ← 0
FOR i ← 1 TO 5
Total ← Total + Scores[i]
NEXT i
OUTPUT Total
追踪:12、19、34、43、53。输出 53。✓
如果数组长度可能改变,就用它的长度而不是固定的 5,例如 FOR i ← 1 TO Length,其中 Length 存放项目个数。
分辨是哪一种错误
| 症状 | 可能原因 | 先检查什么 |
|---|---|---|
| 程序永远结束不了 | 条件永远不会变成假 | 循环有没有改变条件用到的变量? |
| 会停,但答案少了一项 | 上限少一,或用了 < 而不是 <= | 在循环旁写出第一个和最后一个索引 |
| 结尾时崩溃或报错 | 上限多一,读取到数组之外 | 最后一个索引在范围内吗? |
| 5 个项目能用,1 个或 0 个就出错 | 循环假设至少有两个项目 | 手动测试最小的情况 |
任何循环都适用的检查清单
- 写出循环应该处理的第一个和最后一个值。
- 完整追踪第一轮和最后一轮。
- 问:什么会让条件变成假?检查循环是否朝着那个方向前进。
- 用空列表或只有一个项目来测试。
- 检查结果是否合理,例如换一种方式把列表加一遍。
受限伪代码追踪训练器让你逐步查看原创算法,看到每个分支和循环的决定,前提是你的路线允许。安全的 Python 推理沙盒会进行有限制的运行,循环跑太久时会被停止。
接下来看什么
完整的概念请读循环与数组。边界错误另有专页:我的程序能运行,但在边界情况失败。然后试试原创练习里的混合题,整体地图见学习指南。
当追踪还不够的时候
有些同学追踪得很仔细,仍然看不出循环哪里出错,因为背后的想法,例如“变量会自己更新”,在纸上是看不见的。看着你把想法说出来,就很容易找到它。在线一对一 Computer Science 补习从一小时的付费试听课开始,费用按所安排老师确认的价格计算,RM80 起。