《Java数据结构跟算法》第二版 Robert lafore 编程作业 第八章
《Java数据结构和算法》第二版 Robert lafore 编程作业 第八章
《Java数据结构和算法》第二版 Robert lafore 编程作业 第八章
/* 编程作业 8.1 从tree.java程序(清单8.1)出发,把它修改成用用户输入的字母的 字符串建立二叉树(如A、B等等),每个字母在各自的节点中显示。 建立树,让每个包含字母的节点是叶节点。父节点可以有非字母标志 如'+'。保证每个父节点都恰好有两个子节点。不要担心树不平衡。 注意这不是搜索树;没有快速的方法来查找节点。最后结果可以像下 面所示的一样: + + E + D -- -- + C -- -- -- -- -- -- A B -- -- -- -- -- -- -- -- -- -- -- -- -- -- 一种方法是建立一个树的数组。(一组没有连接的树称为森林。)用 用户输入的每个字母作为一个节点。把每个节点作为一棵树,节点就 是根。现在把这些单节点的树放到数组中。下面开始建立一棵以'+' 为根的树,两个单节点树为它的子节点。依次把数组中的单节点树加 到这棵大点的树中。不要担心它是不是平衡树。实际可以用生成的中 间树覆盖数组单元,该数组单元的内容已经加到树中。find()、 insert()和delete()例程只用于搜索树,可以删掉了。保留 displayTree()方法和遍历方法,它们对所有二叉树都通用。 8.2 扩展编程作业8.1中的功能来创建平衡树。一种方法是保证节点尽可 能出现在最底层。开始把每对单节点树建成三节点树,以'+'为根。 这样就有一个三节点树的森林了。合并每对三节点树变成七点节点树 的森林。随着每棵树节点数目的增加,树的数量减少,直到最后只有 一棵树。 8.3 还是从tree.java程序开始。根据用户输入的字符创建树。这次,建 立完全树--除了底层的最右边可能为空,其它层节点完全满的树。字 母要从上到下以及从左到右有序,好像就是建立了一个字符的金字塔。 (这种排列方法与本章前面讨论的三种遍历方法都不对应。)因此, 字符串ABCDEFGHIJ会排列成下面的样子: A B C D E F G H I J -- -- -- -- -- 建立这种树的一种方法是从上到下,而不是像编程作业中前两题那样 从底向上。从建立一个作为最后树的根的节点开始。如果节点编号和 字母排顺序一样,1是根,则编号为n的节点的左子节点的编号为2*n+1。 可以用递归方法,创建两个了节点并在每个子节点中调用它自己的。 节点创建的顺序不需要和它们插入到树中的顺序相同。像编程作业中 前面的题那样,可以删掉Tree类中搜索树的一些方法。 8.4 编写程序根据后缀表达式建立树,如本章图8.11中所示。需要修改 tree.java程序(清单8.1)中的Tree类,和第4单postfix.java程序 (清单4.8)中的ParsePost类。更多细节参考图8.11的解。建好树之后, 遍历树可以得到算术表达式相应的前缀、中缀和后缀表达式。中缀表达 式需要小括号来避免产生模糊不清的表达式。InOrder()方法中,在第 一次递归调用之前加入左括号,在第二次递归调用之后加入右括号。 8.5 编写程序实现哈夫曼编码和解码。需要做如下的工作: Accept a text message,possibly of more than one line. Create a Huffman tree for this message. Create a code table. Encode the message into binary. Decode the message from binary back to text. 如果信息很短,程序可以显示建立好的哈夫曼树。编程作业8.1、8.2 和8.3的方法会有所帮助的。可以用String变量把二进制数存储为字 符1和0的序列。除非确有必要,否则不需要做实际的位处理。 */ package chap08; // tree.java // demonstrates binary tree // to run this program: C>java TreeApp import java.io.*; import java.util.*; // for Stack class //////////////////////////////////////////////////////////////// class Node { public char cchar; public Node leftChild; // this node's left child public Node rightChild; // this node's right child public Node() { } public Node(char c) { cchar = c; } public void displayNode() // display ourself { System.out.print('{'); System.out.print(cchar); System.out.print("} "); } } // end class Node // ////////////////////////////////////////////////////////////// class Tree implements Comparable { // 改成了public public Node root; // first node of tree public int weight; // 权重 // ------------------------- public Tree() // constructor { root = null; } // no nodes in tree yet // 添加了toString()方法 public String toString() { return root.cchar + ""; } // ------------------------- public void traverse(int traverseType) { switch (traverseType) { case 1: System.out.print("\nPreorder traversal: "); preOrder(root); break; case 2: System.out.print("\nInorder traversal: "); inOrder(root); break; case 3: System.out.print("\nPostorder traversal: "); postOrder(root); break; } System.out.println(); } // ------------------------- private void preOrder(Node localRoot) { if (localRoot != null) { System.out.print(localRoot.cchar + " "); preOrder(localRoot.leftChild); preOrder(localRoot.rightChild); } } // ------------------------- private void inOrder(Node localRoot) { if (localRoot != null) { System.out.print("("); inOrder(localRoot.leftChild); System.out.print(localRoot.cchar + " "); inOrder(localRoot.rightChild); System.out.print(")"); } } // ------------------------- private void postOrder(Node localRoot) { if (localRoot != null) { postOrder(localRoot.leftChild); postOrder(localRoot.rightChild); System.out.print(localRoot.cchar + " "); } } // ------------------------- public void displayTree() { Stack globalStack = new Stack(); globalStack.push(root); int nBlanks = 32; boolean isRowEmpty = false; System.out .println("......................................................"); while (isRowEmpty == false) { Stack localStack = new Stack(); isRowEmpty = true; for (int j = 0; j < nBlanks; j++) System.out.print(' '); while (globalStack.isEmpty() == false) { Node temp = (Node) globalStack.pop(); if (temp != null) { System.out.print(temp.cchar); localStack.push(temp.leftChild); localStack.push(temp.rightChild); if (temp.leftChild != null || temp.rightChild != null) isRowEmpty = false; } else { System.out.print("--"); localStack.push(null); localStack.push(null); } for (int j = 0; j < nBlanks * 2 - 2; j++) System.out.print(' '); } // end while globalStack not empty System.out.println(); nBlanks /= 2; while (localStack.isEmpty() == false) globalStack.push(localStack.pop()); } // end while isRowEmpty is false System.out .println("......................................................"); } // end displayTree() // ------------------------- @Override public int compareTo(Object o) { if (o == null) { return -1; } return weight - ((Tree) o).weight; } } // end class Tree // ////////////////////////////////////////////////////////////// public class TreeApp { // 编程作业 8.1 public static void code8_1() throws IOException { System.out.println("请输入至少字符串(至少两个字符):"); String str = getString(); Tree[] array = new Tree[str.length()]; for (int i = 0; i < str.length(); i++) {// 建立单节点树数组 Tree temp = new Tree(); temp.root = new Node(str.charAt(i)); array[i] = temp; } for (int i = 1; i < str.length(); i++) { Tree temp = new Tree(); temp.root = new Node('+'); temp.root.leftChild = array[i - 1].root; temp.root.rightChild = array[i].root; array[i] = temp; } Tree lastTree = array[str.length() - 1]; lastTree.displayTree(); } // 编程作业 8.2 // 这是按题目8.2要求来的平衡二叉树 public static void code8_2() throws IOException { System.out.println("请输入至少字符串(至少两个字符):"); String str = getString(); Tree[] array = new Tree[str.length()]; for (int i = 0; i < array.length; i++) {// 建立单节点树数组 Tree temp = new Tree(); temp.root = new Node(str.charAt(i)); array[i] = temp; } Tree[] tempArray; while (array.length > 1) { tempArray = new Tree[(array.length - 1) / 2 + 1]; int j = -1; int i = 0; for (; i + 1 < array.length; i += 2) { Tree temp = new Tree(); temp.root = new Node('+'); temp.root.leftChild = array[i].root; temp.root.rightChild = array[i + 1].root; tempArray[++j] = temp; } if (i < array.length) { Tree temp = new Tree(); temp.root = new Node('+'); temp.root.leftChild = array[array.length - 1].root; tempArray[++j] = temp; // tempArray[++j] = array[i]; } array = tempArray; } Tree lastTree = array[array.length - 1]; lastTree.displayTree(); } // 编程作业 8.2 // 这才是真正的平衡二叉树 public static void code8_2_1() throws IOException { System.out.println("请输入至少字符串(至少两个字符):"); String str = getString(); Tree[] array = new Tree[str.length()]; for (int i = 0; i < array.length; i++) {// 建立单节点树数组 Tree temp = new Tree(); temp.root = new Node(str.charAt(i)); array[i] = temp; } Tree lastTree = connectTree(array, 0, array.length - 1); lastTree.displayTree(); } private static Tree connectTree(Tree[] array, int left, int right) { if (left == right) { return array[left]; } else { Tree tempTree = new Tree(); tempTree.root = new Node('+'); tempTree.root.leftChild = connectTree(array, left, (right + left) / 2).root; tempTree.root.rightChild = connectTree(array, (right + left) / 2 + 1, right).root; return tempTree; } } // 编程作业 8.3 public static void code8_3() throws IOException { System.out.println("请输入至少字符串(至少两个字符):"); String str = getString(); Tree[] array = new Tree[str.length()]; for (int i = 0; i < array.length; i++) {// 建立单节点树数组 Tree temp = new Tree(); temp.root = new Node(str.charAt(i)); array[i] = temp; } Tree lastTree = connectTree1(array, 0); lastTree.displayTree(); } private static Tree connectTree1(Tree[] array, int index) { if (index * 2 + 1 > array.length - 1) { // 没有子树 return array[index]; } else if (index * 2 + 2 > array.length - 1) { // 有左子树 Tree temp = array[index]; temp.root.leftChild = connectTree1(array, index * 2 + 1).root; return temp; } else { // 有左右子树 Tree temp = array[index]; temp.root.leftChild = connectTree1(array, index * 2 + 1).root; temp.root.rightChild = connectTree1(array, index * 2 + 2).root; return temp; } } public static void main(String[] args) throws IOException { // 编程作业 8.1 - 8.3 // code8_1(); // code8_2(); // code8_2_1(); code8_3(); } // end main() // ------------------------- public static String getString() throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String s = br.readLine(); return s; } // ------------------------- public static char getChar() throws IOException { String s = getString(); return s.charAt(0); } // ------------------------- public static int getInt() throws IOException { String s = getString(); return Integer.parseInt(s); } // ------------------------- } // end class TreeApp // //////////////////////////////////////////////////////////////
package chap08; // postfix.java // parses postfix arithmetic expressions // to run this program: C>java PostfixApp import java.io.*; // for I/O //////////////////////////////////////////////////////////////// class StackX { private int maxSize; private Tree[] stackArray; private int top; // -------------------------- public StackX(int size) // constructor { maxSize = size; stackArray = new Tree[maxSize]; top = -1; } // -------------------------- public void push(Tree j) // put item on top of stack { stackArray[++top] = j; } // -------------------------- public Tree pop() // take item from top of stack { return stackArray[top--]; } // -------------------------- public Tree peek() // peek at top of stack { return stackArray[top]; } // -------------------------- public boolean isEmpty() // true if stack is empty { return (top == -1); } // -------------------------- public boolean isFull() // true if stack is full { return (top == maxSize - 1); } // -------------------------- public int size() // return size { return top + 1; } // -------------------------- public Tree peekN(int n) // peek at index n { return stackArray[n]; } // -------------------------- public void displayStack(String s) { System.out.print(s); System.out.print("Stack (bottom-->top): "); for (int j = 0; j < size(); j++) { System.out.print(peekN(j)); System.out.print(' '); } System.out.println(""); } // -------------------------- } // end class StackX // ////////////////////////////////////////////////////////////// class ParsePost { private StackX theStack; private String input; // -------------------------- public ParsePost(String s) { input = s; } // -------------------------- // 编程作业 8.4 public Tree doParse() { theStack = new StackX(20); // make new stack char ch; int j; Tree num1, num2, interAns; for (j = 0; j < input.length(); j++) // for each char, { ch = input.charAt(j); // read from input theStack.displayStack("" + ch + " "); // *diagnostic* if (ch >= '0' && ch <= '9') { // if it's a number Tree temp = new Tree(); temp.root = new Node(ch); theStack.push(temp); // push it } else // it's an operator { num2 = theStack.pop(); // pop operands num1 = theStack.pop(); Tree temp; switch (ch) // do arithmetic { case '+': temp = new Tree(); temp.root = new Node('+'); temp.root.leftChild = num1.root; temp.root.rightChild = num2.root; theStack.push(temp); break; case '-': temp = new Tree(); temp.root = new Node('-'); temp.root.leftChild = num1.root; temp.root.rightChild = num2.root; theStack.push(temp); break; case '*': temp = new Tree(); temp.root = new Node('*'); temp.root.leftChild = num1.root; temp.root.rightChild = num2.root; theStack.push(temp); break; case '/': temp = new Tree(); temp.root = new Node('/'); temp.root.leftChild = num1.root; temp.root.rightChild = num2.root; theStack.push(temp); break; default: // interAns = 0; } // end switch // theStack.push(interAns); // push result } // end else } // end for interAns = theStack.pop(); // get answer return interAns; } // end doParse() } // end class ParsePost // ////////////////////////////////////////////////////////////// public class PostfixApp { public static void main(String[] args) throws IOException { String input; Tree output; System.out.print("Enter postfix: "); System.out.flush(); input = getString(); // read a string from kbd if (input.equals("")) // quit if [Enter] return; // make a parser ParsePost aParser = new ParsePost(input); output = aParser.doParse(); // do the evaluation // System.out.println("Evaluates to " + output); output.displayTree(); output.traverse(1); output.traverse(2); output.traverse(3); } // end main() // -------------------------- public static String getString() throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String s = br.readLine(); return s; } // -------------------------- } // end class PostfixApp // //////////////////////////////////////////////////////////////
package chap08; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.PriorityQueue; import java.util.Queue; import java.util.Set; import java.util.TreeMap; // ============================================================================= // 编程作业 8.5 public class Huffman { public static Map<Character, String> map_char_code; public static Map<String, Character> map_code_char; static { map_char_code = new HashMap<Character, String>(); // 编码用代码表 map_code_char = new HashMap<String, Character>(); // 解码用代码表 } // 编码分为四步 // 1.统计字符频率 // 2.生成Huffman树 // 3.生成编解码用代码表 // 4.编码字符串 public static String encode(String str) { char[] cchar = str.toCharArray(); // 1.统计字符频率 TreeMap<Character, Integer> map = new TreeMap<Character, Integer>(); for (int i = 0; i < cchar.length; i++) { if (map.containsKey(cchar[i])) { map.put(cchar[i], map.get(cchar[i]).intValue() + 1); } else { map.put(cchar[i], 1); } } // 2.生成Huffman树 // 先由所有字符生成单节点树的森林 // 然后根据优先级合成单节点树为一棵树 Queue<Tree> forest = new PriorityQueue<Tree>(); Set<Map.Entry<Character, Integer>> set = map.entrySet(); Iterator<Map.Entry<Character, Integer>> it = set.iterator(); while (it.hasNext()) { // 生成单节点树 Map.Entry<Character, Integer> en = it.next(); Tree temp = new Tree(); temp.root = new Node(en.getKey()); temp.weight = en.getValue(); forest.add(temp); } while (forest.size() > 1) { // 把单节点树合并为一棵树立 Tree t1 = forest.remove(); Tree t2 = forest.remove(); Tree t3 = new Tree(); t3.root = new Node(); t3.weight = t1.weight + t2.weight; t3.root.leftChild = t1.root; t3.root.rightChild = t2.root; forest.add(t3); } Tree t = forest.remove(); // 最后一棵树 // 3.生成编解码用map String code = ""; preOrder(t.root, code, map_char_code, map_code_char); // 4.编码字符串 StringBuffer output = new StringBuffer(); for (int i = 0; i < cchar.length; i++) { output.append(map_char_code.get(cchar[i])); } return output.toString(); } // 遍历Huffman树生成编解码代码表 private static void preOrder(Node localRoot, String code, Map<Character, String> map_char_code, Map<String, Character> map_code_char) { if (localRoot != null) { if (localRoot.cchar != '\0') { map_char_code.put(localRoot.cchar, code); map_code_char.put(code, localRoot.cchar); } preOrder(localRoot.leftChild, code + "0", map_char_code, map_code_char); preOrder(localRoot.rightChild, code + "1", map_char_code, map_code_char); } } // 解码 // 根据确码代码表还原信息 public static String decode(String str) { StringBuffer result = new StringBuffer(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < str.length(); i++) { sb.append(str.charAt(i)); if (map_code_char.get(sb.toString()) != null) { result.append(map_code_char.get(sb.toString())); sb = new StringBuffer(); } } return result.toString(); } public static void main(String[] args) { String code = encode("SUSIE SAYS IT IS EASY!"); System.out.println(code); String str = decode(code); System.out.println(str); } // ------------------------- public static String getString() throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String s = br.readLine(); return s; } } // =============================================================================