AP CSA 2.12:循环的非正式运行分析
Earlier lessons focused on writing and tracing loops. In this lesson, you will determine final variable values and count exactly how many times a statement executes.
前面的课程重点是编写和追踪循环。本节课将进一步判断循环结束后的变量值,并准确计算某条语句会执行多少次。
To analyze a loop, track the values that actually reach the loop body—not just the numbers written in the loop header. 分析循环时,要追踪真正进入循环体的变量值,而不能只看循环头中出现的数字。
Core Concepts:
核心知识点
1. Trace the Variables Before Counting
先追踪变量,再判断次数
What are the final values of var1 and var2?
var1 和 var2 的最终值分别是多少?
int var1 = 0;
int var2 = 2;
while (var2 != 0 && var1 / var2 >= 0)
{
var1++;
var2--;
}
Answer:
var1 = 2
var2 = 0
Use a trace table:
使用追踪表:
| Stage | var1 |
var2 |
Condition result |
|---|---|---|---|
| Before the loop 进入循环前 |
0 |
2 |
true |
| After iteration 1 第 1 次迭代后 |
1 |
1 |
Checked again |
| After iteration 2 第 2 次迭代后 |
2 |
0 |
Checked again |
| Final check 最后一次检查 |
2 |
0 |
false |
On the final condition check:
最后一次检查条件时:
var2 != 0
0 != 0
false
Because the left side of && is already false, Java does not evaluate:
因为 && 左边已经为假,所以 Java 不会计算:
var1 / var2 >= 0
Therefore, the code does not divide by zero.
因此,这段代码不会发生除以零的错误。
2. Use a Trace Table for Changing Variables
使用追踪表记录变量变化
Consider:
观察下面的代码:
int x = 2;
int y = 5;
while (y > 2 && x < y)
{
x++;
y--;
}
What are the final values?
最终值是什么?
Answer:
x = 4
y = 3
Trace every complete iteration:
追踪每一次完整迭代:
| Stage | x |
y |
y > 2 |
x < y |
Complete condition |
|---|---|---|---|---|---|
| Before the loop 进入循环前 |
2 |
5 |
true |
true |
true |
| After iteration 1 第 1 次迭代后 |
3 |
4 |
true |
true |
true |
| After iteration 2 第 2 次迭代后 |
4 |
3 |
true |
false |
false |
When the condition becomes false, the loop stops immediately. The body does not run a third time.
当条件变为假时,循环立即停止,不会执行第三次循环体。
A reliable trace table should include:
一个可靠的追踪表应该记录:
-
all starting values; 所有变量的初始值;
-
each value after the loop body finishes; 每次循环体结束后的变量值;
-
the condition that finally becomes false. 最终让循环停止的条件。
3. Statement Execution Count
语句执行次数
A statement execution count tells us how many times a particular statement runs.
语句执行次数表示某一条语句实际执行了多少次。
for (int i = 3; i < 7; i++)
{
System.out.print("*");
}
The loop variable takes these values:
循环变量的实际取值是:
3 4 5 6
Therefore:
因此:
-
the loop body runs
4times; -
System.out.print("*");executes4times; -
four stars are printed.
-
循环体执行
4次; -
System.out.print("*");执行4次; -
最终输出四个星号。
****
Do not count 7. When i becomes 7, the condition i < 7 is false, so the body does not run.
不能把 7 算进去。当 i 变成 7 时,i < 7 为假,因此不会进入循环体。
4. Counting a Single Loop
计算单层循环次数
For loops that increase or decrease by 1, first identify:
对于每次增加或减少 1 的循环,先确定:
-
the smallest value that enters the body;
-
the largest value that enters the body.
-
能够进入循环体的最小值;
-
能够进入循环体的最大值。
Then use:
然后使用:
largest value - smallest value + 1
Example 1: Boundary excluded
例一:不包含边界
for (int i = 3; i < 8; i++)
{
System.out.println(i);
}
The actual values are:
实际取值为:
3 4 5 6 7
7 - 3 + 1 = 5 iterations
Example 2: Boundary included
例二:包含边界
for (int i = 3; i <= 8; i++)
{
System.out.println(i);
}
The actual values are:
实际取值为:
3 4 5 6 7 8
8 - 3 + 1 = 6 iterations
| Loop condition | Largest value entering the body |
|---|---|
counter < limit |
limit - 1 |
counter <= limit |
limit |
counter > limit |
limit + 1 |
counter >= limit |
limit |
This shortcut assumes the loop variable changes by exactly 1.
这个快捷公式假设循环变量每次正好变化 1。
For a different update such as i += 2, list the values or calculate the step size carefully.
如果更新方式是 i += 2 等其他步长,应列出实际取值或单独计算。
5. Count the Values, Not Just the Distance
计算实际取值,而不是只看距离
How many times does this loop run?
下面的循环执行多少次?
for (int i = 2; i <= 10; i += 2)
{
System.out.print("*");
}
Answer: Five times.
i = 2, 4, 6, 8, 10
The body executes once for each of those five values.
循环体会针对这五个值各执行一次。
The formula:
公式:
largest - smallest + 1
does not directly work here because the update is i += 2, not i++.
在这里不能直接使用“最大值减最小值加一”,因为更新方式是 i += 2,而不是 i++。
A simple AP-safe strategy is to list the values:
一种可靠的 AP 做题方法是直接列出取值:
2 → 4 → 6 → 8 → 10 → 12 stops
6. Fixed Nested Loops: Multiply the Counts
固定次数嵌套循环:次数相乘
How many stars are printed?
下面会输出多少个星号?
for (int row = 0; row < 5; row++)
{
for (int col = 0; col < 10; col++)
{
System.out.print("*");
}
System.out.println();
}
Answer: 50 stars.
外层循环:
row = 0, 1, 2, 3, 4
5 iterations
内层循环:
col = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
10 iterations
The inner loop runs ten times during each of the five outer iterations:
在五次外层迭代中,内层循环每次都执行十次:
5 × 10 = 50
| Loop | Iterations | Meaning |
|---|---|---|
| Outer loop 外层循环 |
5 |
Five rows 五行 |
| Inner loop 内层循环 |
10 per row |
Ten stars in each row 每行十个星号 |
| Inner statement 内层语句 |
50 total |
Total stars 星号总数 |
Multiplication works because the inner loop executes the same number of times for every outer iteration.
之所以能够直接相乘,是因为每次外层迭代中,内层循环的执行次数都相同。
7. Non-Rectangular Nested Loops: Add the Counts
非固定嵌套循环:逐轮相加
Consider:
观察下面的代码:
int count = 0;
for (int row = 1; row <= 4; row++)
{
for (int col = 1; col <= row; col++)
{
count++;
}
}
System.out.println(count);
What is printed?
输出是什么?
Answer:
10
The inner-loop limit depends on row.
内层循环的结束范围取决于 row。
row |
Inner values of col |
Inner iterations |
|---|---|---|
1 |
1 |
1 |
2 |
1, 2 |
2 |
3 |
1, 2, 3 |
3 |
4 |
1, 2, 3, 4 |
4 |
Add the counts:
把每一轮的次数相加:
1 + 2 + 3 + 4 = 10
Do not calculate:
不能直接计算:
4 × 4
The inner loop does not run four times during every outer iteration.
因为内层循环并不是在每次外层迭代中都执行四次。
For the pattern:
对于下面这种模式:
1 + 2 + 3 + ... + n
the total can be calculated with:
总数可以使用:
n(n + 1) / 2
For n = 4:
当 n = 4 时:
4(4 + 1) / 2 = 10
8. Condition Checks and Body Executions Are Different
条件检查次数与循环体执行次数不同
Consider:
观察:
for (int i = 0; i < 3; i++)
{
System.out.println(i);
}
The body executes three times:
循环体执行三次:
i = 0
i = 1
i = 2
However, the condition is checked four times:
但是,条件一共检查四次:
0 < 3 → true
1 < 3 → true
2 < 3 → true
3 < 3 → false
| What is being counted? | Count |
|---|---|
| Loop-body executions 循环体执行次数 |
3 |
println executionsprintln 执行次数 |
3 |
| Condition evaluations 条件检查次数 |
4 |
Updates using i++i++ 执行次数 |
3 |
Read the question carefully. “How many times does the loop body run?” and “How many times is the condition evaluated?” are different questions.
要仔细阅读题目。“循环体执行多少次”和“条件检查多少次”不是同一个问题。
9. Common Beginner Mistakes
常见初学者错误
| Mistake | Why it is wrong | Correct understanding |
|---|---|---|
| Counting the excluded boundary. 把不包含的边界也算进去。 |
A condition such as i < 7 does not allow i = 7 into the body.i < 7 不允许 i = 7 进入循环体。 |
List only the values that make the condition true. 只列出让条件为真的变量值。 |
Using the shortcut formula when the step is not 1.步长不是 1 时仍直接套公式。 |
The loop may skip values. 循环可能会跳过一些数值。 |
List the values or account for the step size. 列出实际取值或考虑步长。 |
| Multiplying all nested-loop limits. 直接把嵌套循环的边界数字相乘。 |
The limits may not equal the iteration counts. 边界值不一定就是迭代次数。 |
Calculate each loop’s actual iterations first. 先分别计算实际迭代次数。 |
| Multiplying a non-rectangular nested loop. 对变化的内层循环直接相乘。 |
The inner-loop count changes with the outer variable. 内层次数会随着外层变量变化。 |
Add the inner counts for each outer iteration. 把每轮内层次数相加。 |
| Confusing body executions with condition checks. 混淆循环体执行次数与条件检查次数。 |
The final false condition is checked but does not run the body. 最后一次假条件会被检查,但不会执行循环体。 |
Identify the exact statement the question asks you to count. 先确定题目要求统计哪条语句。 |
| Predicting division by zero without applying short-circuit evaluation. 没有考虑短路求值就判断会除以零。 |
The unsafe right side may be skipped. 右边的危险表达式可能不会执行。 |
Evaluate the left side of && first.先计算 && 左边。 |
10. Debugging Example
调试例子
The following condition is intended to avoid division by zero:
下面的条件原本想避免除以零:
int numerator = 8;
int denominator = 1;
while (numerator / denominator >= 0 && denominator != 0)
{
numerator++;
denominator--;
}
After one iteration:
第一次迭代后:
numerator = 9
denominator = 0
Java returns to the condition and evaluates the left side first:
Java 返回条件后,会先计算左边:
numerator / denominator >= 0
This attempts to divide by zero and causes an ArithmeticException.
这会尝试除以零,并导致 ArithmeticException。
This is a runtime error.
这属于运行时错误。
Fixed code
int numerator = 8;
int denominator = 1;
while (denominator != 0 && numerator / denominator >= 0)
{
numerator++;
denominator--;
}
Now the safety check appears first.
现在,安全检查位于前面。
When denominator becomes 0:
当 denominator 变成 0 时:
denominator != 0 → false
Short-circuit evaluation skips the division.
短路求值会跳过除法运算。
| Version | First condition checked | Result when denominator is 0 |
|---|---|---|
| Unsafe 不安全 |
numerator / denominator >= 0 |
Runtime error 运行时错误 |
| Safe 安全 |
denominator != 0 |
Right side is skipped 跳过右边 |
11. Mini Practice
小练习
Practice 1: Trace Final Values
练习一:追踪最终值
What are the final values?
最终值是什么?
int a = 1;
int b = 6;
while (a < b)
{
a += 2;
b--;
}
Answer:
a = 5
b = 4
Trace:
a = 1, b = 6 → condition true
a = 3, b = 5 → condition true
a = 5, b = 4 → condition false
Practice 2: Count a Single Loop
练习二:计算单层循环次数
How many times is "AP" printed?
"AP" 会输出多少次?
for (int i = 4; i < 9; i++)
{
System.out.println("AP");
}
Answer: Five times.
i = 4, 5, 6, 7, 8
Practice 3: Count with a Different Step
练习三:计算不同步长
How many times does the body run?
循环体执行多少次?
for (int i = 1; i <= 10; i += 3)
{
System.out.println(i);
}
Answer: Four times.
i = 1, 4, 7, 10
Practice 4: Rectangular Nested Loop
练习四:固定次数嵌套循环
How many times does count++ execute?
count++ 会执行多少次?
int count = 0;
for (int i = 2; i < 8; i++)
{
for (int j = 1; j <= 5; j++)
{
count++;
}
}
Answer: 30 times.
Outer loop: 2, 3, 4, 5, 6, 7 → 6 iterations
Inner loop: 1, 2, 3, 4, 5 → 5 iterations
6 × 5 = 30
Practice 5: Non-Rectangular Nested Loop
练习五:非固定次数嵌套循环
What is the final value of count?
count 的最终值是多少?
int count = 0;
for (int i = 1; i <= 3; i++)
{
for (int j = 0; j < i; j++)
{
count++;
}
}
Answer: 6
The inner loop runs:
内层循环分别执行:
1 time when i = 1
2 times when i = 2
3 times when i = 3
1 + 2 + 3 = 6
Quick Checklist
快速检查清单
Before answering a Topic 2.12 question, check:
做 2.12 的题目之前,检查:
-
What exact statement are you being asked to count? 题目要求统计的是哪一条语句?
-
What are all variables’ starting values? 所有变量的初始值是什么?
-
Should you create a trace table? 是否应该创建追踪表?
-
What values actually enter the loop body? 哪些变量值真正进入了循环体?
-
Is the ending boundary included or excluded? 是否包含结束边界?
-
Does the loop update by
1, or does it use another step size? 循环每次变化1,还是使用其他步长? -
Is the largest valid value
limitorlimit - 1? 最大合法值是limit还是limit - 1? -
Are you counting body executions or condition checks? 你统计的是循环体执行次数,还是条件检查次数?
-
Does the final false condition add another body execution? 最后一次假条件是否会增加一次循环体执行?
-
For fixed nested loops, did you calculate both iteration counts before multiplying? 对于固定次数的嵌套循环,是否先分别计算次数再相乘?
-
Does the inner-loop count remain the same for every outer iteration? 每次外层迭代中,内层循环次数是否相同?
-
If the inner count changes, did you add the counts instead of multiplying? 如果内层次数发生变化,是否逐轮相加而不是直接相乘?
-
Could the natural-number sum formula apply? 是否可以使用自然数求和公式?
-
Does short-circuit evaluation skip an unsafe expression? 短路求值是否会跳过危险表达式?
-
Is a division-by-zero check placed before the division? 除零检查是否位于除法表达式之前?
-
Have you checked the final values after the loop stops? 循环停止后,是否检查了变量的最终值?