《Java数据结构和算法》第二版 Robert lafore 编程作业 第六章
/*
6.1 假设买了一个价格便宜的掌上电脑,但是发现它内置的芯片不能做乘法,只能做
加法。摆脱这种窘境需要自己编写程序,写的是一个递归的方法mult(),它的参
数是x和y返回值是x乘它.当这个方法调用自身或者当它返回的时候,加法是否起
作用了?
6.2 在第8章"二叉树"中,我们将看到二叉树,在它的每一个节点中确实有两个子树。
如果使用字符在屏幕上画一棵二叉树,可以在顶层有一个节点,在下一层有两个,
然后是4、8、16个,依此类推。下面是一棵最底层有16个字符的树的样子:
--------X-------
----X-------X---
--X---X---X---X-
-X-X-X-X-X-X-X-X
XXXXXXXXXXXXXXXX
(注意最下面的一行,应当向右移动半个字符宽,但是在字符模式中做不到。)
可以使用递归的makeBranches()方法来画这个树,这个方法的参数为left和
right,它们是水平范围的端点。当第一次进入这个程序的时候,left等于0,而
且right是所有行中字符的数目(包括短线)减一。在这行范围的中间画一个X。
然后这个方法调用自己两次:一次左一半的范围,一次右一半的范围。当这个范
围太小的时候返回。你可能想要把所有的短线和X都放到一个数组中,并且一次性
显示数组,或许可以使用display()方法。编写main()调用makeBranches()和
display()来画这棵树。允许main()决定显示的每一行的宽度(32,64或者其他
的任何值)。确保存放显示字符的数组不会比所需要的空间大。行数(图中为五)
和每一行的宽度有什么关系?
6.3 应用递归的算法来实现求一个数的乘方,如在这一章接近结尾处的"求一个数的乘
方"部分所讲。写递归的power()方法以及一个main()来测试它。
6.4 写一个能解决背包问题的程序,任意给定背包的容量以及一系列物品的重量,设
把这些重量值存在一个数组中。提示:递归方法knapsack()的参数是目标重量和
剩下物品开始位置的数组下标。
6.5 应用一个递归的方法来显示由一群人组队的所有可能方案(由n个人每次挑k个)。
编写递归的showTeams()方法和一个main()方法来提示用户输入人群的人数以及
组队的人数,以此来作为showTeams()的参数,然后显示所有的组合。
*/
package chap06;
//=======================================================================
//编程作业 6.1
public class Multiplication {
// multiplicand 被乘数
// multiplier 乘数
// multiply 乘
public int multiply(int multiplicand, int multiplier) {
if (multiplier == 1) {
return multiplicand;
} else {
return multiplicand + multiply(multiplicand, multiplier - 1);
}
}
public static void main(String[] args) {
Multiplication mutiplication = new Multiplication();
int result = mutiplication.multiply(6, 8);
System.out.println(result);
}
}
// =======================================================================
package chap06;
// =============================================================================
// 编程作业 6.2
public class BinaryTreeShow {
private char[][] lines;
// number 一行最大显示字符数
public BinaryTreeShow(int number) {
int rows = 1;
int numberDivide = number;// 不要直接用number去除,后面还有用到number
while ((numberDivide = numberDivide / 2) != 0) {// 行数 number和row的关系
rows++; // 2^(row-1) = number 2^(5-1)=16
} // 当number=16时,row=5
lines = new char[rows][number];
for (int i = 0; i < rows; i++) { // 初始化数组
for (int j = 0; j < number; j++) {
lines[i][j] = '-';
}
}
}
public void display() {
for (int i = 0; i < lines.length; i++) { // 初始化数组
for (int j = 0; j < lines[i].length; j++) {
System.out.print(lines[i][j]);
}
System.out.println();
}
}
public void makeBranches(int left, int right) {
int number = right - left + 1;
int row = 0;
int muberDivide = number; // 不要直接用number去除,后面还有用到number
while ((muberDivide = muberDivide * 2) <= lines[0].length) {
row++;// 计算当前行号
}
if (number == 1) {// 基值条件
lines[row][left] = 'X';
return;
} else {
int mid = (left + right) / 2 + 1;
lines[row][mid] = 'X';
makeBranches(left, mid - 1);
makeBranches(mid, right);
}
}
public void makeTree() {
makeBranches(0, lines[0].length - 1);
}
public static void main(String[] args) {
BinaryTreeShow binaryTreeShow = new BinaryTreeShow(16);
binaryTreeShow.makeTree();
binaryTreeShow.display();
}
}
// =============================================================================
package chap06;
//编程作业 6.3
//mathematics 数学,数学运算
//int的范围 [-2^32~2^31-1] -2147483648到2147483647
public class Mathematics {
// 求x的y次方 x^y
// 对于 y总是偶数时
// 2^8 = (2*2)^(8/2)= 4^4
// 4^4 = (4*4)^(4/2)=16^2
// 16^2 = (16*16)^(2/2) = 256^1
// 256^1 = 256
// 对于y出现是奇数时
// 3^18 = (3*3)^(18/2) = 9^9
// 9^9 = 9*(9^8)= 9*((9*9)^(8/2)) = 9*(81^4)
// 9*(81^4)=9*((81*81)^(4/2))=9*(6561^2)
// 9*(6561^2)=9*((6561*6561)^(2/2))=9*43046721^1
// 9*43046721^1 = 9*43046721
public int power(int x, int y) {
if (y == 1) {
return x;
} else {
if (y % 2 == 0) {
return power(x * x, y / 2);
} else {
return x * power(x * x, y / 2);
}
}
}
public static void main(String[] args) {
Mathematics mathematics = new Mathematics();
int result = mathematics.power(3, 18);
System.out.println(result);
}
}
package chap06;
// =============================================================================
// 编程作业 6.4
public class Knapsack {
private int[] weights; // 可供选择的重量
private boolean[] selects; // 记录是否被选择
public Knapsack(int[] weights) {
this.weights = weights;
selects = new boolean[weights.length];
}
// 找所有可能的解
// total总重量
// index可供选择的重量
public void knapsack(int total, int index) {
if (total < 0 || total > 0 && index >= weights.length) {// 基值,没找到解
return;
}
if (total == 0) { // 基值,找到解
for (int i = 0; i < index; i++) {
if (selects[i] == true) {
System.out.print(weights[i] + " ");
}
}
System.out.println();
return;
}
selects[index] = true;
knapsack(total - weights[index], index + 1);
selects[index] = false;
knapsack(total, index + 1);
}
public static void main(String[] args) {
Knapsack knapsack = new Knapsack(new int[] { 11, 8, 7, 6, 5, 4, 3 });
knapsack.knapsack(20, 0);
}
}
// =============================================================================
package chap06;
//编程作业 6.5
//方法一
public class Group {
private char[] persons; // 组中所有可供选择的成员
private boolean[] selects; // 标记成员选中与否
public Group(char[] persons) {
this.persons = persons;
selects = new boolean[persons.length];
}
public void showTeams(int teamNumber) {
showTeams(persons.length, teamNumber);
}
// =============================================
// 找所有可能的解
// totalNuber 总共有多少人供选择
// teamNuber 需要选择多少人
// =============================================
// 从个n人中取出k个人的所可能方案,表示为方法参数(n,k)
// 求(n,k)的所有解
// 当k=0时得一个解,n<k时无解
// 否则(n,k)-->(n-1,k-1)+(n-1,k)
// =============================================
// 列如 :从3个人中选2个人,此时参数为(3,2)
// (3,2)-->(2,1)+(2,2)-->(1,0)+(1,1)+(1,1)+(1,2)
// (1,0)得到一个解,(1,2)无解
// (1,0)+(1,1)+(1,1)+(1,2)-->(1,1)+(1,1)
// (1,1)+(1,1)-->(0,0)+(0,1)+(0,0)+(0,1)
// (0,0)得到一个解,(0,1)无解
// 所以(3,2)一共有 3个解
// 列如 :从3个人中选3个人,此时参数为(3,3)
// (3,3)-->(2,2)+(2,3)-->(2,2)-->(1,1)+(1,2)-->(1,1)-->(0,0)+(0,1)-->(0,0)
// 即(3,3)有一个解
// =============================================
private void showTeams(int totalNumber, int teamNumber) {
if (teamNumber == 0) { // teamNumber=0时, 找到一个解
for (int i = 0; i < selects.length; i++) {
if (selects[i] == true) {
System.out.print(persons[i] + " ");
}
}
System.out.println();
return;
}
if (totalNumber < teamNumber) { // totalNuber< teamNumber,无解
return;
}
selects[persons.length - totalNumber] = true;
showTeams(totalNumber - 1, teamNumber - 1);
selects[persons.length - totalNumber] = false;
showTeams(totalNumber - 1, teamNumber);
}
public static void main(String[] args) {
Group group = new Group(new char[] { 'A', 'B', 'C', 'D', 'E' });
group.showTeams(3);
}
}
package chap06;
//编程作业 6.5
//方法二
public class Group1 {
private char[] persons; // 组中所有可供选择的成员
private boolean[] selects; // 标记成员选中与否
public Group1(char[] persons) {
this.persons = persons;
selects = new boolean[persons.length];
}
public void showTeams(int teamNumber) {
showTeams(teamNumber, 0);
}
// =============================================
// 找所有可能的解
// teamNumber需要选择的队员数
// index从第几个队员开始选择
// =============================================
// 从n个人中取出k个人的所可能方案
// 此处方法参数有些变化(n,k)应写成(k,i)(i=0,1,2,...)
// 当k=0时得一个解,i>=n时无解
// 否则(k,i)-->(k-1,i+1)+(k,i+1)
// =============================================
// 列如 :从3个人中选2个人,
// 参数应写成(2,0)
// (2,0)-->(1,1)+(2,1)-->(0,2)+(1,2)+(1,2)+(2,2)
// (0,2)得一解
// (1,2)+(1,2)+(2,2)-->(0,3)+(1,3)+(0,3)+(1,3)+(1,3)+(2,3)
// (0,3)得一解,(1,3)无解,(2,3)无解,有两个(0,3)
// 所以(2,0)有三个解
// =============================================
private void showTeams(int teamNumber, int index) {
if (teamNumber == 0) { // 当teamNuber=0时 找到
for (int i = 0; i < selects.length; i++) {
if (selects[i] == true) {
System.out.print(persons[i] + " ");
}
}
System.out.println();
return;
}
if (index >= persons.length) {// index超过可供选择的人的数,未找到
return;
}
selects[index] = true;
showTeams(teamNumber - 1, index + 1);
selects[index] = false;
showTeams(teamNumber, index + 1);
}
public static void main(String[] args) {
Group1 group = new Group1(new char[] { 'A', 'B', 'C', 'D', 'E' });
group.showTeams(3);
}
}