《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-XXXXXXXXXXXXXXXXX(注意最下面的一行,應當向右移動半個字元寬,但是在字元模式中做不到。)可以使用遞迴的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.1public 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.2public class BinaryTreeShow {private char[][] lines;// number 一行最大顯示字元數public BinaryTreeShow(int number) {int rows = 1;int numberDivide = number;// 不要直接用number去除,後面還有用到numberwhile ((numberDivide = numberDivide / 2) != 0) {// 行數 number和row的關係rows++;// 2^(row-1) = number 2^(5-1)=16}// 當number=16時,row=5lines = 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去除,後面還有用到numberwhile ((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到2147483647public 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*43046721public 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.4public 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);}}