《Java数据结构和算法》第二版 Robert lafore 编程作业 第八章
转自:http://blog.csdn.net/zhch152/article/details/7948559
/*
编程作业
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;
}
}
// =============================================================================