Mr.Mou @ ShiShi AP Center

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?

var1var2 的最终值分别是多少?

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:

一个可靠的追踪表应该记录:

  1. all starting values; 所有变量的初始值;

  2. each value after the loop body finishes; 每次循环体结束后的变量值;

  3. 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:

因此:

****

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 的循环,先确定:

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 executions
println 执行次数
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 的题目之前,检查: