| Learning Objective | Essential Knowledge |
|---|---|
4.1.A |
|
4.1.B |
|
4.1.C |
|
数据集合
AP 计算机科学 A · 第 4 主题
4.1
数据采集的伦理与社会问题
大纲
来源:美国大学理事会 AP 课程与考试说明
收集数据的程序提出隐私(privacy)和同意(consent)的问题。只收集需要的、保护它,并对它的使用诚实。数据能携带偏见(bias),若它不公平地代表每个人,导致不公平的结果——一个随着存储信息而来的责任。
| 英文 | 中文 | 拼音 |
|---|---|---|
| privacy | 隐私 | yǐn sī |
| consent | 同意 | tóng yì |
| bias | 偏见 | piān jiàn |
4.2
使用数据集导论
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.2.A |
|
来源:美国大学理事会 AP 课程与考试说明
一个单一的变量持有一个值;真实的问题需要存储许多相关的值——一个班级名册、像素、传感器读数。一个数据结构(data structure)组织一个搜集,以便我们能高效地存储、找到和处理项。AP 课程用三个:数组(array)、ArrayList,和 2D 数组。
| 英文 | 中文 | 拼音 |
|---|---|---|
| data structure | 数据结构 | shù jù jié gòu |
| array | 数组 | shù zǔ |
4.3
数组的创建与访问
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.3.A |
|
来源:美国大学理事会 AP 课程与考试说明
一个数组(array)是一个固定大小的、有序的相同类型值的搜集。索引从 0 到 length - 1:

int[] nums = new int[5]; // five zeros
int[] vals = {3, 1, 4, 1, 5}; // initialized
int first = vals[0]; // 3
int n = vals.length; // 5 (a field, not a method)
访问 0..length-1 之外的一个索引抛出一个 ArrayIndexOutOfBoundsException。
4.4
数组遍历
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.4.A |
|
来源:美国大学理事会 AP 课程与考试说明
用一个 for 循环(给出索引)或一个增强 for / for-each(enhanced for / for-each)循环(给出每个值,只读)遍历(traverse)一个数组:
for (int i = 0; i < a.length; i++) { a[i] *= 2; } // can modify
for (int v : a) { System.out.println(v); } // read each value
| 英文 | 中文 | 拼音 |
|---|---|---|
| Traverse | 遍历 | biàn lì |
4.5
实现数组算法
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.5.A |
|
来源:美国大学理事会 AP 课程与考试说明
掌握这些模式:计算一个和或平均、找最大/最小、计数满足一个条件的项、检查一个重复,和反转或移位元素。每一个都是一个带连续结果的遍历:
int sum = 0;
for (int v : a) sum += v;
double avg = (double) sum / a.length;
4.6
使用文本文件
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.6.A |
|
来源:美国大学理事会 AP 课程与考试说明
File 和 IOException 在 java.io 里,所以一个读文件的程序需要 import java.io.*;。打开一个文件可能失败(它也许不存在),Java 强制你处理这一点——最简单的方式是在方法头上加 throws IOException。然后一个 Scanner 逐行读文件,用 hasNext... 在读之前测试:
import java.io.*;
...
public static void readFile() throws IOException {
Scanner f = new Scanner(new File("data.txt"));
while (f.hasNextLine()) {
String line = f.nextLine();
}
}
用 nextInt()、nextDouble() 或 nextBoolean() 读有类型的记号时,如果下一个记号是错误的类型,会抛出一个 InputMismatchException——例如当文件里下一个东西是单词 cat 时调用 nextInt()。
4.7
包装类
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.7.A |
|
来源:美国大学理事会 AP 课程与考试说明
一个 ArrayList 存储对象,不是基本类型,所以一个基本类型被包装在一个对象里:Integer 包装 int,Double 包装 double。Java 用自动装箱(autoboxing)(int 到 Integer)和拆箱(unboxing)(再回去)自动做这个,所以你能写 list.add(5) 和 int x = list.get(0)。
| 英文 | 中文 | 拼音 |
|---|---|---|
| autoboxing | 自动装箱 | zì dòng zhuāng xiāng |
4.8
ArrayList 方法
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.8.A |
|
来源:美国大学理事会 AP 课程与考试说明
一个 ArrayList(动态数组)在你添加或移除项时增长和收缩。用 <> 里的元素类型声明它:
ArrayList<String> names = new ArrayList<String>();
names.add("Amy"); // append
names.add(0, "Bob"); // insert at index
names.get(0); // read
names.set(1, "Cara"); // replace
names.remove(0); // delete, shifts the rest left
names.size(); // count (a method, unlike array.length)
| 英文 | 中文 | 拼音 |
|---|---|---|
| ArrayList | 动态数组 | dòng tài shù zǔ |
4.9
ArrayList 遍历
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.9.A |
|
来源:美国大学理事会 AP 课程与考试说明
用一个索引循环或一个 for-each 循环遍历,就像数组(用 size() 和 get(i)):
for (int i = 0; i < list.size(); i++) { ... list.get(i) ... }
for (String s : list) { ... }
考试技能: 当在一个索引循环里移除项时,要么向后循环,要么在一次移除之后不递增 i ——否则移除会把元素向左移动而你跳过一个。而且绝不要在用一个 for-each 循环遍历一个 ArrayList 时添加或移除元素:在循环中途改变它的大小会抛出一个 ConcurrentModificationException,所以每当你必须移除时用一个索引循环(向后,如上)。
4.10
实现 ArrayList 算法
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.10.A |
|
来源:美国大学理事会 AP 课程与考试说明
与数组相同的算法——最大/最小、计数、求和——加上数组不能轻易做的插入和删除。一个常见的任务是移除所有匹配一个条件的元素,小心地处理索引移位。
4.11
二维数组的创建与访问
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.11.A |
|
来源:美国大学理事会 AP 课程与考试说明
一个 2D 数组(2D array)是一个网格(行和列)——一个数组的数组:

int[][] grid = new int[3][4]; // 3 rows, 4 columns
grid[r][c] = 7; // row r, column c
int rows = grid.length; // 3
int cols = grid[0].length; // 4
Index a 2D array by row and column
A 2D array is a grid addressed by [row][col]. Move the indices and watch which cell they select — row first, then column, both counting from 0.
| 英文 | 中文 | 拼音 |
|---|---|---|
| 2D array | 二维数组 | èr wéi shù zǔ |
4.12
二维数组遍历
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.12.A |
|
来源:美国大学理事会 AP 课程与考试说明
用嵌套循环(nested loops)访问每个单元格——外层遍历行、内层遍历列(行主序(row-major order)):
for (int r = 0; r < grid.length; r++)
for (int c = 0; c < grid[0].length; c++)
System.out.print(grid[r][c]);
| 英文 | 中文 | 拼音 |
|---|---|---|
| row-major order | 行主序 | xíng zhǔ xù |
4.13
实现二维数组算法
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.13.A |
|
来源:美国大学理事会 AP 课程与考试说明
典型的网格任务:求一行或一列的和、找网格里的最大值、计数匹配的单元格,或求一条对角线的和(r == c 的地方)。每一个都是一个带连续结果的嵌套遍历。
4.14
查找算法
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.14.A |
|
来源:美国大学理事会 AP 课程与考试说明
- 线性搜索(linear search)依次检查每个元素——在任何列表上起作用,取最多 $n$ 步。
- 二分搜索(binary search)只在一个排序的列表上起作用:检查中间、然后丢弃不能包含目标的那一半,重复。它取约 $\log_2 n$ 步——在大数据上快得多。


int lo = 0, hi = a.length - 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (a[mid] == target) return mid;
else if (a[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
考试技能: 二分搜索需要排序的数据;知道它做多少次比较以及 lo、hi、mid 如何更新。
Worked example. 在排序的数组 {3, 9, 14, 23, 31, 42, 55}(索引 0–6)里搜索 target = 40。开始 lo=0, hi=6:
mid = (0+6)/2 = 3,a[3]=23 < 40,所以lo = 4;mid = (4+6)/2 = 5,a[5]=42 > 40,所以hi = 4;mid = (4+4)/2 = 4,a[4]=31 < 40,所以lo = 5;- 现在
lo (5) > hi (4),所以循环结束——40不存在。
每一步把范围减半,所以即使这次未命中也只取三次比较。
Compare linear and binary search
Linear search checks every element in turn; binary search halves a sorted list each step. Watch binary search reach the target in far fewer comparisons.
| 英文 | 中文 | 拼音 |
|---|---|---|
| Linear search | 线性搜索 | xiàn xìng sōu suǒ |
| Binary search | 二分搜索 | èr fēn sōu suǒ |
4.15
排序算法
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.15.A |
|
来源:美国大学理事会 AP 课程与考试说明
- 选择排序(selection sort)反复找到最小的剩余元素并把它交换到位。
- 插入排序(insertion sort)增长一个排序的前部,把每个新元素插入到它所属的地方。

两者都简单,平均取约 $n^2$ 步——对小数组还行。能够跟踪每一趟之后的数组。
Watch a sorting algorithm order a list
A sort rearranges elements into order. Step through selection/insertion sort to see the sorted region grow one element at a time.
| 英文 | 中文 | 拼音 |
|---|---|---|
| Selection sort | 选择排序 | xuǎn zé pái xù |
| Insertion sort | 插入排序 | chā rù pái xù |
4.16
递归
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.16.A |
|
来源:美国大学理事会 AP 课程与考试说明
递归(recursion)是一个在一个更小的输入上调用它自己的方法。它需要一个停止调用的基本情况(base case),和一个朝基本情况移动的递归情况(recursive case):
public static int factorial(int n) {
if (n <= 1) return 1; // base case
return n * factorial(n - 1); // recursive case
}
没有一个可达的基本情况,递归从不停止(一个栈溢出)。
递归和迭代是可以互换的。任何递归解法都能用一个循环(迭代方式)改写,而任何循环也都能用递归改写 —— 它们解决的是同一类问题。上面的 factorial 与一个迭代版本效果完全相同:
public static int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; i++) result *= i; // same answer, no self-call
return result;
}
所以这个选择关乎清晰度,而非能力:对于具有自相似结构的问题(树、归并排序),递归读起来很自然;而迭代则避免了每一步都压入一个调用帧的内存开销。考试可能会要求你把其中一种转换成另一种。
Unfold a recursive call
A recursive method calls itself on a smaller input until it hits a base case, then the results fold back up. Step through to watch the calls stack and unwind.
| 英文 | 中文 | 拼音 |
|---|---|---|
| Recursion | 递归 | dì guī |
| base case | 基本情况 | jī běn qíng kuàng |
4.17
递归查找与排序
大纲
| Learning Objective | Essential Knowledge |
|---|---|
4.17.A |
|
4.17.B |
|
4.17.C |
|
来源:美国大学理事会 AP 课程与考试说明
递归驱动高效的算法。二分搜索能被递归地写(搜索正确的那一半)。归并排序(merge sort)把数组分成一半、递归地排序每一半,然后归并两个排序的一半——取约 $n\log_2 n$ 步,在大数据上比选择或插入排序快得多。

Worked example. 跟踪 factorial(4)。每个调用推迟给一个更小的:factorial(4) = 4 * factorial(3) = 4 * 3 * factorial(2) = 4 * 3 * 2 * factorial(1)。factorial(1) 命中基本情况并返回 1,所以调用向内展开:2 * 1 = 2,然后 3 * 2 = 6,然后 4 * 6 = 24。把每个调用写在它返回值的上方是跟踪递归的可靠方式。
考试技能: 通过写出每个调用和它的返回值来跟踪一个递归方法,并知道归并排序的效率($n\log n$)击败 $n^2$ 的简单排序。
| 英文 | 中文 | 拼音 |
|---|---|---|
| Merge sort | 归并排序 | guī bìng pái xù |
4.17
考试技巧
- 权衡收集数据的好处和害处——这个单元通过简短的书面论证考查,不是代码。
- 保护个人身份信息(PII)(personally identifiable information)并在上下文里解释隐私和安全风险。
- 命名真实的害处:数据泄露、监视,和来自不具代表性数据的算法偏见。
- 当你重用代码或数据时尊重知识产权和许可。
- 给出一个具体的、有理由的答案——一个模糊的"它可能是坏的"不赢得分数。
本主题的互动课程
逐步学习,并即时检测练习。