6.11 练习
本章的示例代码位于仓库 ThinkJavaCode 的目录 ch06 中,有关如何下载这个仓库,请参阅前言中的“使用示例代码”一节。做以下的练习前,建议你先编译并运行本章的示例。
如果你还没有阅读 A.7 节,那么现在正是阅读的好时机。该节介绍了 JUnit——一款测试值方法的有效工具。
练习6-1
如果你对某种做法是否合法、不合法的结果是什么存在疑问,让编译器来解答是一种不错的方法。请尝试回答下面的问题。
(1) 如果调用一个值方法,但不用它返回的结果,即既没有将其赋给变量,也没有将其用于表达式中,结果将如何呢?
(2) 如果将一个 void 方法用于表达式中,结果将如何呢?例如,尝试执行代码 System.out.println("boo!") + 7。
练习6-2
编写一个名为 isDivisible 的方法,让它接受两个整数——n 和 m,并在 n 能被 m 整除时返回 true,否则返回 false。
练习6-3
给定 3 根棍子,可能能够将它们排列成三角形,也可能不行。例如,如果其中一根棍子长 12 英寸,另外两根都为 1 英寸,那么就无法将 3 根棍子相互相连。给定任意 3 根棍子的长度,可通过下面的简单测试来判断它们能否组成三角形:
只要其中 1 根棍子的长度大于其他 2 根棍子的总长,它们就无法组成三角形。
请编写一个名为 isTriangle 的方法,让它接受 3 个整数参数,并根据长度分别为这 3 个整数的棍子能否组成三角形而返回 true 或 false。这个练习的重点是用条件语句编写值方法。
练习6-4
很多计算都可用“乘加”运算来更简洁地表示出来,这种运算接受 3 个操作数,并计算 a * b + c 的结果。有些处理器甚至提供了对浮点数执行这种运算的硬件实现。
(1) 创建一个程序,并命名为 Multadd.java。
(2) 编写一个名为 multadd 的方法,让它接受 3 个 double 参数,并返回 a * b + c。
(3) 编写一个 main 方法,并在其中测试方法 multadd:调用 multadd 并传递几个简单的实参,如 1.0、2.0、3.0。
(4) 另外,在 main 中用方法 multadd 来计算下述表达式的值:

(5) 编写一个名为 expSum 的方法,让它接受一个 double 参数,并调用 multadd 来计算下述表达式的值:

在这个练习的最后一部分,你需要编写一个方法,这个方法要能调用你编写的另一个方法。在这种情况下,最好先仔细测试要调用的方法,否则你可能面临同时调试两个方法的困境。
这个练习的目的之一是锻炼你的模式匹配能力——能够看出要解决的问题是通用问题的特例。
练习6-5
以下程序的输出是什么?
public static void main(String[] args) {boolean flag1 = isHoopy(202);boolean flag2 = isFrabjuous(202);System.out.println(flag1);System.out.println(flag2);if (flag1 && flag2) {System.out.println("ping!");}if (flag1 || flag2) {System.out.println("pong!");}}public static boolean isHoopy(int x) {boolean hoopyFlag;if (x % 2 == 0) {hoopyFlag = true;} else {hoopyFlag = false;}return hoopyFlag;}public static boolean isFrabjuous(int x) {boolean frabjuousFlag;if (x > 0) {frabjuousFlag = true;} else {frabjuousFlag = false;}return frabjuousFlag;}
这个练习旨在确保你明白逻辑运算符和值方法的执行流程。
练习6-6
在这个练习中,你可以用栈图来帮助理解下述递归程序的执行流程:
public static void main(String[] args) {System.out.println(prod(1, 4));}public static int prod(int m, int n) {if (m == n) {return n;} else {int recurse = prod(m, n - 1);int result = n * recurse;return result;}}
(1) 绘制一个栈图,指出对 prod 的最后一次调用结束前,这个程序的状态是什么样的。
(2) 这个程序的输出是什么?(先尝试用纸和笔来回答这个问题,再通过运行代码来检查答案。)
(3) 简单地说说 prod 是做什么的(无需涉及其工作原理的细节)。
(4) 修改方法 prod,删除其中的临时变量 recurse 和 result。提示:else 分支只需要一行代码。
练习6-7
编写一个名为 oddSum 的递归方法,它接受一个正奇数——n,并返回 1~n(闭区间)所有奇数的和。请先考虑基线条件,并用临时变量调试解决方案。每次调用 oddSum 时都打印参数值 n 可能大有帮助。
练习6-8
这个练习的目标是将递归定义转换为 Java 方法。阿克曼函数的定义如下(其中 m 和 n 都是非负整数):

请编写一个名为 ack 的方法,让它接受两个 int 参数,然后计算并返回阿克曼函数的值。
测试你编写的 ack 方法:在 main 中调用它,并显示它返回的值。请注意,阿克曼函数值的递增速度非常快,测试时应使用较小的 m 和 n(不超过 3)。
练习6-9
编写一个名为 power 的递归方法,它接受 double 参数 x 和 int 参数 n,并返回 xn 的值。
提示:这种运算的递归定义为 xn = x·xn-1。另外别忘了,零以外的任何数字的 0 次方都为 1。
选做题:n 为偶数时,利用公式 xn=(xn/2)2 来提高这个方法的效率。
