8.9 生成直方图
前面的代码有些重复,但只要范围数不多,这是完全可以接受的。然而,如果我们要计算每个分数出现的次数,就必须编写 100 行代码:
int count0 = inRange(scores, 0, 1);int count1 = inRange(scores, 1, 2);int count2 = inRange(scores, 2, 3);...int count99 = inRange(scores, 99, 100);
我们需要存储 100 个计数器,最好还能用索引来访问计数器。换言之,我们需要一个数组!
下面的代码片段创建了一个包含 100 个计数器的数组,每种可能的分数一个。它遍历分数,并用 inRange 计算每种分数出现的次数,并将结果存储在数组中:
int[] counts = new int[100];for (int i = 0; i < counts.length; i++) {counts[i] = inRange(scores, i, i + 1);}
注意,我们在三个地方使用了循环变量 i:一处用作索引访问数组 counts,两处用于设置 inRange 的两个实参。这些代码可行,但在效率方面还有改进空间。这个循环每次调用 inRange 时都遍历整个数组。
更好的做法是只遍历数组一次;计算每个成绩所在的范围,并将相应的计数器加 1。下面的代码在只遍历数组一次的情况下生成直方图:
int[] counts = new int[100];for (int i = 0; i < scores.length; i++) {int index = scores[i];counts[index]++;}
这个循环每次执行时,都选择数组 scores 中的一个元素,并将其用作索引来将数组 counts 中相应的元素加 1。因为这些代码只遍历数组 scores 一次,所以其效率高得多。
