8.12 练习

本章的示例代码位于仓库 ThinkJavaCode 的目录 ch08 中,有关如何下载这个仓库,请参阅前言中的“使用示例代码”一节。做以下的练习前,建议你先编译并运行本章的示例。

练习8-1

这个练习旨在用本章的一些示例来练习封装。

(1) 以 8.6 节中的代码为基础,编写一个名为 powArray 的方法,让它接受一个 double 数组 a,并返回一个新数组,其中包含数组 a 中的所有元素的平方。泛化这个方法使其接受另一个参数,该参数要指定计算元素的几次方。

(2) 以 8.10 节的代码为基础,编写一个名为 histogram 的方法,让它接受一个 int 数组,其中存储了 0~100(不包括 100)的成绩,并返回一个包含 100 个计数器的直方图。泛化这个方法使其接受另一个指定计数器数量的参数。

练习8-2

这个练习旨在让你阅读代码,并识别本章介绍过的遍历模式。下面的方法难以阅读,因为它们给变量指定的不是有意义的名称,而是水果名。

  1. public static int banana(int[] a) {
  2. int kiwi = 1;
  3. int i = 0;
  4. while (i < a.length) {
  5. kiwi = kiwi * a[i];
  6. i++;
  7. }
  8. return kiwi;
  9. }
  10. public static int grapefruit(int[] a, int grape) {
  11. for (int i = 0; i < a.length; i++) {
  12. if (a[i] == grape) {
  13. return i;
  14. }
  15. }
  16. return -1;
  17. }
  18. public static int pineapple(int[] a, int apple) {
  19. int pear = 0;
  20. for (int pine: a) {
  21. if (pine == apple) {
  22. pear++;
  23. }
  24. }
  25. return pear;
  26. }

用一句话描述每个方法的功能,无需涉及其相关的工作原理细节。指出每个变量扮演的角色。

练习8-3

下述程序的输出是什么?请绘制一个栈图,以显示该程序在 mus 返回前的状态。用几个词描述 mus 的功能。

  1. public static int[] make(int n) {
  2. int[] a = new int[n];
  3. for (int i = 0; i < n; i++) {
  4. a[i] = i + 1;
  5. }
  6. return a;
  7. }
  8. public static void dub(int[] jub) {
  9. for (int i = 0; i < jub.length; i++) {
  10. jub[i] *= 2;
  11. }
  12. }
  13. public static int mus(int[] zoo) {
  14. int fus = 0;
  15. for (int i = 0; i < zoo.length; i++) {
  16. fus += zoo[i];
  17. }
  18. return fus;
  19. }
  20. public static void main(String[] args) {
  21. int[] bob = make(5);
  22. dub(bob);
  23. System.out.println(mus(bob));
  24. }

练习8-4

编写一个名为 indexOfMax 的方法,让它接受一个 int 数组,并返回其中最大元素的索引。你能用改进的 for 循环来编写这个方法吗?为什么?

练习8-5

埃拉托斯特尼筛法是一种古老而简单的算法,用于找出小于指定值的所有素数。这种算法的相关详细信息请参阅 https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

请编写一个名为 sieve 的方法,让它接受一个 int 参数 n,并返回一个 boolean 数组,指出 0~n-1 的各个数是否为素数。

练习8-6

编写一个名为 areFactors 的方法,让它接受一个 int 参数 n 和一个 int 数组,并在这个数组的所有元素都是 n 的因数(即 n 可被所有元素整除)时返回 true

练习8-7

编写一个名为 arePrimeFactors 的方法,让它接受一个 int 参数 n 和一个 int 数组,并在这个数组的所有元素都为素数且它们的乘积为 n 时返回 true

练习8-8

本章介绍的很多数组遍历模式也可以用递归方式来实现。这种做法虽然不常见,却是一个很有用的练习。

(1) 编写一个名为 maxInRange 的方法,让它接受一个 int 数组和两个索引(lowIndexhighIndex),并在这两个索引指定的范围内(闭区间)找出最大的元素。

这个方法必须是递归的。如果范围为 1,即 lowIndex==highIndex,那么就意味着这个范围只包含一个元素,因此它就是最大的。所以这是基线条件。

如果这个范围包含多个元素,我们可将这个范围分成两部分,并在两部分中分别找出最大的元素,再在这两个最大的元素中找出更大的那个。

(2) maxInRange 这样的方法可能难以使用。要找出数组中的最大元素,我们必须将范围指定为整个数组。

  1. double max = maxInRange(a, 0, a.length - 1);

编写一个名为 max 的方法,让它接受一个数组,然后用 maxInRange 找出并返回其中的最大元素。