**差一错误(off-by-one error)**指循环多运行了一轮或少运行了一轮。它是算法题中最常见的错误之一,考试经常给出一个有问题的循环,要求你修复。
这一课建立在追踪计数控制和条件控制循环的基础上,属于重复与数组模块。一旦出现数组,它就更重要了。
怎样找出出错的那一行?
按以下顺序进行:
- 用数字说明循环应该做什么。例如”把前 10 个整数相加,所以 10 轮,答案 55”。
- 追踪第一轮和最后一轮。
- 数一数代码实际运行了几轮。
- 比较。如果代码少了或多了一轮,就检查起始值、结束值和比较符号。
例题详解
一位程序员想求整数 1 到 10 的总和。
Total ← 0
FOR i ← 1 TO 9
Total ← Total + i
NEXT i
OUTPUT Total
循环取值为 1 到 9,共 9 轮。任务需要 10 轮。
| i | 之后的 Total |
|---|---|
| 1 | 1 |
| 2 | 3 |
| 3 | 6 |
| 4 | 10 |
| 5 | 15 |
| 6 | 21 |
| 7 | 28 |
| 8 | 36 |
| 9 | 45 |
输出是 45,但 1 到 10 的总和是 55。缺少的值是 10,而 45 + 10 = 55。修复方法是改结束值:
FOR i ← 1 TO 10
WHILE 循环也可能把同样的错误藏在条件里。下面这个版本本应输出 3 的前四个倍数,即 3、6、9 和 12。
Count ← 0
WHILE Count <= 4 DO
Count ← Count + 1
OUTPUT Count * 3
ENDWHILE
Count = 0、1、2、3、4 时测试都为真,所以有 5 轮。它输出 3、6、9、12 和 15。把条件改成 Count < 4,则 Count = 0、1、2、3 时运行,输出 3、6、9 和 12,这才是正确的。
要留意的错误
常见的失误是修改输出,而不是修改循环。
错误的修法: “总和是 45,应该是 55,所以写
OUTPUT Total + 10。”这只对这一组输入给出 55。循环仍然漏掉最后一个值,换任何其他结束值都会出错。
纠正的方法是修改循环边界,让它运行正确的轮数。然后追踪第二个小例子,例如数字 1 到 3(总和 6)来确认。
自我检测
1. 数组 Score[1:5] 存有五个值,代码是 FOR i ← 0 TO 4。哪里错了?怎样修复?
查看答案
数组的位置从 1 到 5。位置 0 不存在,而位置 5 从未被访问。修复为 FOR i ← 1 TO 5。
2. FOR i ← 5 TO 12 运行几轮?
查看答案
取值为 5、6、7、8、9、10、11、12,共 8 轮。检查:12 - 5 + 1 = 8。
3. 这个循环应该只输出 2、4 和 6,却输出了 2、4、6 和 8。请给出修复方法。
n ← 0
WHILE n < 8 DO
n ← n + 2
OUTPUT n
ENDWHILE
查看答案
n = 0、2、4 和 6 时测试为真,所以运行四轮,最后输出 8。把条件改成 WHILE n < 6。这样 n = 0、2 和 4 通过测试,输出为 2、4 和 6。
接下来学什么
接下来用一个正确的循环扫描列表:在给定列表中找最大值。伪代码追踪训练器可以让你逐步运行有问题的循环,观察第一轮和最后一轮。
计算机科学补习的老师可以带来新的出错循环,请你在动笔之前先解释该如何修复。