跟着老师学Java Day 21 - Day 29

Day 21: 二叉树的深度遍历的递归实现

在递归实现求深度和结点数量部分,关键是要列出所有情况,比如:无叶子结点,只有左孩子、只有右孩子,左右孩子都有的情况。

21.1 代码

package datastructure;

import  java.util.Arrays;

/**
 * Binary tree with char type elements.
 * 
 * @author XuQiong
 *
 */
public class BinaryCharTree {
	/**
	 * The value in char.
	 */
	char value;
	
	/**
	 * The left child.
	 */
	BinaryCharTree leftChild;
	
	/**
	 * The right child.
	 */
	BinaryCharTree rightChild;
	
	/**
	 * ***********************
	 * The first constructor.
	 * 
	 * @param paraName
	 *    			The value.
	 * ***********************
	 */
	public BinaryCharTree(char paraName) {
		value = paraName;
		leftChild = null;
		rightChild = null;
	}
	
	/**
	 * **********************
	 * Manually construct a tree. Only for testing.
	 * **********************
	 */
	public static BinaryCharTree manualConstructTree() {
		// Step 1. Construct a tree with only one node.
		BinaryCharTree resultTree = new BinaryCharTree('a');
		
		//Step 2. Construct all nodes. The first node is root.
		//BinaryCharTreeNode tempTreeA = resultTree.root;
		BinaryCharTree tempTreeB = new BinaryCharTree('b');
		BinaryCharTree tempTreeC = new BinaryCharTree('c');
		BinaryCharTree tempTreeD = new BinaryCharTree('d');
		BinaryCharTree tempTreeE = new BinaryCharTree('e');
		BinaryCharTree tempTreeF = new BinaryCharTree('f');
		BinaryCharTree tempTreeG = new BinaryCharTree('g');
		
		//Step 3. Link all nodes.
		resultTree.leftChild = tempTreeB;
		resultTree.rightChild = tempTreeC;
		tempTreeB.rightChild = tempTreeD;
		tempTreeC.leftChild = tempTreeE;
		tempTreeD.leftChild = tempTreeF;
		tempTreeD.rightChild = tempTreeG;
		
		return resultTree;
	}// Of manualConstructTree
	
	/**
	 * ***********************************
	 * Pre-order visit.
	 * ***********************************
	 */
	public void preOderVisit() {
		System.out.println("" + value + "");
		if(leftChild !=  null) {
			leftChild.preOderVisit();
		}// Of if
		if(rightChild !=  null) {
			rightChild.preOderVisit();
		}// Of if
	}// Of preOrderVisit
	
	/**
	 * **********************************
	 * In-order visit.
	 * **********************************
	 */
	public void inOderVisit() {
		if(leftChild !=  null) {
			leftChild.preOderVisit();
		}// Of if
		System.out.println("" + value + "");	
		if(rightChild !=  null) {
			rightChild.preOderVisit();
		}// Of if
	}// Of inOrderVisit
	
	/**
	 * *********************************
	 * Post-order visit.
	 * *********************************
	 */
	public void postOrderVisit() {
		if(leftChild !=  null) {
			leftChild.preOderVisit();
		}// Of if
		
		if(rightChild !=  null) {
			rightChild.preOderVisit();
		}// Of if
		
		System.out.println("" + value + "");	
	}// Of postOrderVisit
	
	/**
	 * **********************************
	 * Get the depth of the binary tree.
	 * 
	 * @return The depth. It is 1 if there is only one code, i.e., the root.
	 * **********************************
	 */
	public int getDepth() {
		// It is a leaf.
		if (leftChild == null && rightChild == null) {
			return 1;
		}// Of if
		
		//Only rightChild.
		if (leftChild == null) {
			return rightChild.getDepth() + 1;
		} 
		
		//Only leftChild.
		if (rightChild == null) {
			return leftChild.getDepth() + 1;
		} 
		
		//Both rightChild and leftChild.
		if(leftChild.getDepth() > rightChild.getDepth()) {
			return leftChild.getDepth() + 1;
		} else {
			return rightChild.getDepth() + 1;
		}// Of if 		
	}// Of depth
	
	/**
	 * ***********************************
	 * Get the number of the nodes.
	 * 
	 * @return The number of nodes.
	 * ***********************************
	 */
	public int getNumNodes() {
		// It is a leaf.
		if(leftChild == null && rightChild == null) {
			return 1;
		}// Of if
		
		//Only rightChild.
		if (leftChild == null) {
			return rightChild.getNumNodes() + 1;
		} 
				
		//Only leftChild.
		if (rightChild == null) {
			return leftChild.getNumNodes() + 1;
		} 
				
		//Both rightChild and leftChild.			
		return leftChild.getNumNodes() + rightChild.getNumNodes() + 1;
	}
	
	/**
	 * ************************************
	 * The entrance of the program.
	 * 
	 * @param args
	 *          Not used now.
	 * ************************************
	 */
	public static void main(String args[]) {
		BinaryCharTree tempTree = manualConstructTree();
		System.out.println("\r\nPreorder visit:");
		tempTree.preOderVisit();
		
		System.out.println("\r\nInorder visit:");
		tempTree.inOderVisit();
		
		System.out.println("\r\nPostorder visit:");
		tempTree.postOrderVisit();
		
		System.out.println("\r\n\r\nThe depth is:" + tempTree.getDepth());
		System.out.println("\r\n\r\nThe number of nodes is:" + tempTree.getNumNodes());	
	}// Of main
}// Of BinaryCharTree

22.2 运行结果

 Day 22:二叉树的存储

今天遇到一个bug,main 函数中少写了一个参数 String args[],程序无法识别为主函数,无法运行。

将二叉树结点与索引存储在两个向量中,需要利用队列,对二叉树进行广度优先遍历,保证访问的结点顺序是从上到下,从左到右。

22.1 代码实现

package datastructure;

import  java.util.Arrays;
import  datastructure.*;
/**
 * Binary tree with char type elements.
 * 
 * @author XuQiong
 *
 */
public class BinaryCharTree {
	/**
	 * The value in char.
	 */
	char value;
	
	/**
	 * The left child.
	 */
	BinaryCharTree leftChild;
	
	/**
	 * The right child.
	 */
	BinaryCharTree rightChild;
	
	/**
	 * The value of nodes according to breadth first traversal.
	 */
	char[] valuesArray;

	/**
	 * The indices in the complete binary tree.
	 */
	int[] indicesArray;

	
	/**
	 * ***********************
	 * The first constructor.
	 * 
	 * @param paraName
	 *    			The value.
	 * ***********************
	 */
	public BinaryCharTree(char paraName) {
		value = paraName;
		leftChild = null;
		rightChild = null;
	}
	
	/**
	 * **********************
	 * Manually construct a tree. Only for testing.
	 * **********************
	 */
	public static BinaryCharTree manualConstructTree() {
		// Step 1. Construct a tree with only one node.
		BinaryCharTree resultTree = new BinaryCharTree('a');
		
		//Step 2. Construct all nodes. The first node is root.
		//BinaryCharTreeNode tempTreeA = resultTree.root;
		BinaryCharTree tempTreeB = new BinaryCharTree('b');
		BinaryCharTree tempTreeC = new BinaryCharTree('c');
		BinaryCharTree tempTreeD = new BinaryCharTree('d');
		BinaryCharTree tempTreeE = new BinaryCharTree('e');
		BinaryCharTree tempTreeF = new BinaryCharTree('f');
		BinaryCharTree tempTreeG = new BinaryCharTree('g');
		
		//Step 3. Link all nodes.
		resultTree.leftChild = tempTreeB;
		resultTree.rightChild = tempTreeC;
		tempTreeB.rightChild = tempTreeD;
		tempTreeC.leftChild = tempTreeE;
		tempTreeD.leftChild = tempTreeF;
		tempTreeD.rightChild = tempTreeG;
		
		return resultTree;
	}// Of manualConstructTree
	
	/**
	 * ***********************************
	 * Pre-order visit.
	 * ***********************************
	 */
	public void preOderVisit() {
		System.out.println("" + value + "");
		if(leftChild !=  null) {
			leftChild.preOderVisit();
		}// Of if
		if(rightChild !=  null) {
			rightChild.preOderVisit();
		}// Of if
	}// Of preOrderVisit
	
	/**
	 * **********************************
	 * In-order visit.
	 * **********************************
	 */
	public void inOderVisit() {
		if(leftChild !=  null) {
			leftChild.preOderVisit();
		}// Of if
		System.out.println("" + value + "");	
		if(rightChild !=  null) {
			rightChild.preOderVisit();
		}// Of if
	}// Of inOrderVisit
	
	/**
	 * *********************************
	 * Post-order visit.
	 * *********************************
	 */
	public void postOrderVisit() {
		if(leftChild !=  null) {
			leftChild.preOderVisit();
		}// Of if
		
		if(rightChild !=  null) {
			rightChild.preOderVisit();
		}// Of if
		
		System.out.println("" + value + "");	
	}// Of postOrderVisit
	
	/**
	 * **********************************
	 * Get the depth of the binary tree.
	 * 
	 * @return The depth. It is 1 if there is only one code, i.e., the root.
	 * **********************************
	 */
	public int getDepth() {
		// It is a leaf.
		if (leftChild == null && rightChild == null) {
			return 1;
		}// Of if
		
		//Only rightChild.
		if (leftChild == null) {
			return rightChild.getDepth() + 1;
		} 
		
		//Only leftChild.
		if (rightChild == null) {
			return leftChild.getDepth() + 1;
		} 
		
		//Both rightChild and leftChild.
		if(leftChild.getDepth() > rightChild.getDepth()) {
			return leftChild.getDepth() + 1;
		} else {
			return rightChild.getDepth() + 1;
		}// Of if 		
	}// Of depth
	
	/**
	 * ***********************************
	 * Get the number of the nodes.
	 * 
	 * @return The number of nodes.
	 * ***********************************
	 */
	public int getNumNodes() {
		// It is a leaf.
		if(leftChild == null && rightChild == null) {
			return 1;
		}// Of if
		
		//Only rightChild.
		if (leftChild == null) {
			return rightChild.getNumNodes() + 1;
		} 
				
		//Only leftChild.
		if (rightChild == null) {
			return leftChild.getNumNodes() + 1;
		} 
				
		//Both rightChild and leftChild.			
		return leftChild.getNumNodes() + rightChild.getNumNodes() + 1;
	}
	
	
	/**
	 * **************************
	 * Convert the tree to data arrays, including a char array and an int array.
	 * The results are stored in two number variables.
	 * 
	 * @see #valuesArray
	 * @see #indicesArray
	 * **************************
	 */
	public void toDataArrays() {
		//Initialize arrays.
		int tempLength = getNumNodes();
		
		valuesArray = new char[tempLength];
		indicesArray = new int[tempLength];
		int i = 0;
		
		//Traverse and convert at the same time.
		CircleObjectQueue tempQueue = new CircleObjectQueue();
		tempQueue.enqueue(this);
		CircleIntQueue tempIntQueue = new CircleIntQueue();
		tempIntQueue.enqueue(0);
		
		BinaryCharTree tempTree = (BinaryCharTree) tempQueue.dequeue();
		int tempIndex = tempIntQueue.dequeue();
		while(tempTree != null) {
			valuesArray[i] = tempTree.value;
			indicesArray[i] = tempIndex;
			i++;
			
			if (tempTree.leftChild != null) {
				tempQueue.enqueue(tempTree.leftChild);
				tempIntQueue.enqueue(tempIndex * 2 + 1);
			}// Of if
			
			if (tempTree.rightChild != null) {
				tempQueue.enqueue(tempTree.rightChild);
				tempIntQueue.enqueue(tempIndex * 2 + 2);
			}// Of if
			
			tempTree = (BinaryCharTree) tempQueue.dequeue();
			tempIndex = tempIntQueue.dequeue();
		}// Of while       	
	}// Of toDataArray
	
	/**
	 * ************************************
	 * The entrance of the program.
	 * 
	 * @param args
	 *          Not used now.
	 * ************************************
	 */
	public static void main(String args[]) {
		BinaryCharTree tempTree = manualConstructTree();
		System.out.println("\r\nPreorder visit:");
		tempTree.preOderVisit();
		
		System.out.println("\r\nInorder visit:");
		tempTree.inOderVisit();
		
		System.out.println("\r\nPostorder visit:");
		tempTree.postOrderVisit();
		
		System.out.println("\r\n\r\nThe depth is:" + tempTree.getDepth());
		System.out.println("\r\n\r\nThe number of nodes is:" + tempTree.getNumNodes());	
		
		tempTree.toDataArrays();
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));
	}// Of main
}// Of BinaryCharTree

22.3 运行结果

 Day 23: 使用具有通用性的队列

23.1 代码

/**
	 * **************************
	 * Convert the tree to data arrays, including a char array and an int array.
	 * The results are stored in two number variables.
	 * 
	 * @see #valuesArray
	 * @see #indicesArray
	 * **************************
	 */
	public void toDataArraysObjectQueue() {
		int tempLength = getNumNodes();
		
		CircleObjectQueue tempQueue = new CircleObjectQueue();
		tempQueue.enqueue(this);
		CircleObjectQueue tempIntQueue = new CircleObjectQueue();
		Integer tempIndexInteger = Integer.valueOf(0);
		tempIntQueue.enqueue(tempIndexInteger);
		
		valuesArray = new char[tempLength];
		indicesArray = new int[tempLength];
		int i = 0;
		
		BinaryCharTree tempTree = (BinaryCharTree)tempQueue.dequeue();
		Integer tempIndex = (Integer)tempIntQueue.dequeue();
		
		while(tempTree !=  null) {
			valuesArray[i] = tempTree.value;
			indicesArray[i] = tempIndex.intValue();
			i++;
			
			
			if (tempTree.leftChild != null) {
				tempQueue.enqueue(tempTree.leftChild);
				tempIndexInteger = Integer.valueOf(2 * i + 1);
				tempIntQueue.enqueue(tempIndexInteger);
			}// Of if
			
			if (tempTree.rightChild != null) {
				tempQueue.enqueue(tempTree.rightChild);
				tempIndexInteger = Integer.valueOf(2 * i + 2);
				tempIntQueue.enqueue(tempIndexInteger);
			}// Of if
			
			tempTree = (BinaryCharTree)tempQueue.dequeue();
			tempIndex = (Integer)tempIntQueue.dequeue();
		
		}// Of while
		
	}// Of toDataArraysObjectQueue

23.2 运行结果

 Day 24:二叉树的建立

1、在给对象数组的成员变量赋值时,出现如下问题:

错误代码:

BinaryCharTree[] tempAllNodes = new BinaryCharTree[tempNumNodes]

tempAllNodes[i].value = paraDataArray[i];

正确代码:

BinaryCharTree[] tempAllNodes = new BinaryCharTree[tempNumNodes]
tempAllNodes[i] = new BinaryCharTree(paraDataArray[i]);

错误原因:

在定义对象数组时,只定义了null,在给对象赋值时,还需要用构造函数定义对象才可以。

2、在第二步,在二叉树结点之间建立关系时,使用单层循环,未能实现。调试时发现错误。

3、这个过程整个的思路其实和手动建立二叉树一致。

24.1 代码实现

/**
	 * *************************
	 * The second constructor. The parameters must be correct since no validity.
	 * Check is undertaken.
	 * 
	 * @param paraDataArray  The array for data.
	 * @param paraIndicesArray The array for indices.
	 * *************************
	 */
	public BinaryCharTree(char[] paraDataArray, int[] paraIndicesArray) {
		
		int tempNumNodes = paraDataArray.length;
		
		//Step 1. Construct all nodes. The first node is root.
		BinaryCharTree[] tempAllNodes = new BinaryCharTree[tempNumNodes];
		for (int i = 0; i < tempNumNodes; i++) {
			//tempAllNodes[i].value = paraDataArray[i];
			tempAllNodes[i] = new BinaryCharTree(paraDataArray[i]);
		}// Of for i
		
		//Step 2. Link all nodes.
		for (int i = 1; i < tempNumNodes; i++) {
			for(int j = 0; j < i; j++) {
				if (paraIndicesArray[i] == paraIndicesArray[j] * 2 + 1) {
					tempAllNodes[j].leftChild = tempAllNodes[i];
					break;
				} else if (paraIndicesArray[i] == paraIndicesArray[j] * 2 + 2){
					tempAllNodes[j].rightChild = tempAllNodes[i];
					break;
				}// Of if
			}// Of for j
		}// Of for i
		
		//Step 3. The root is the first node.
		value = tempAllNodes[0].value;
		leftChild = tempAllNodes[0].leftChild;
		rightChild = tempAllNodes[0].rightChild;
	}// Of the second constructor

24.2 运行结果

Day 25:二叉树深度遍历的栈实现(中序)

 1、将char类型的变量 ch,存入Object 类型的栈中,需要进行如下操作:

其中方法1和方法2原理相同,将基本数据类型char 转换为Character 对象,方法2 由于版本更新被弃用。方法三中,默认将char 类型自动封箱为Character 。

  1. tempObjectStack.push(Character.valueOf(ch)); 
  2. tempObjectStack.push(new Character(ch));
  3. tempObjectStack.push(ch);

 2、Character 和 char 的区别:

Character是char的包装类,就像Integer和int,包装类和基本类型可以自动转换叫自动封箱和自动解封。

char ch='a';
Character ch1=ch;//自动封箱
Character c=new Character(a);
char c1=c;//自动解封

3、面向对象中this 的用法 ,还没看懂。

4、中序遍历栈实现部分,有点没想明白。

25.1 对象栈代码实现

package datastructure.stack;

public class ObjectStack {
	/**
	 * The depth.
	 */
	public static final int MAX_DEPTH = 10;
	
	/**
	 * The actual depth.
	 */
	int depth;
	
	/**
	 * The data.
	 */
	Object[] data;
	
	/**
	 * ***************
	 * Construct an empty sequential list.
	 * ***************
	 */
	public ObjectStack() {
		depth = 0;
		data = new Object[MAX_DEPTH];
	}// Of the first constructor
	
	/**
	 * ********************
	 * Override the method claimed in Object, the superclass of any class.
	 * ********************
	 */
	public String toString() {
		String resultString = "";
		for (int i = 0; i < depth; i++) {
			resultString += data[i];
		}// Of for i
		return resultString;
	}
	
	/**
	 * *********************
	 * Push an element.
	 * 
	 * @param paraObject
	 * 				The given Object.
	 * @return Success or not.
	 * ********************
	 */
	public boolean push(Object paraObject) {
		if(depth == MAX_DEPTH) {
			System.out.println("The Object stack is full!");
			return false;
		}
		data[depth] = paraObject;
		depth++;
		return true;
	}// Of push
	
	/**
	 * ************************
	 * Pop an element.
	 * 
	 * @return The Object at the top of the stack.
	 * ************************
	 */
	public Object pop() {
		if(depth == 0) {
			System.out.println("Nothing to pop!");
			return null;
		}// Of if
		Object reultObject = data[depth - 1];
		depth--;
		return reultObject;
	}// Of pop
	
	/**
	 * ************************
	 * Is the stack empty?
	 * 
	 * @return True if empty.
	 * ************************
	 */
	public boolean isEmpty() {
		if(depth == 0) {
			System.out.println("The stack is empty!");
			return true;
		} else {
			return false;
		}// Of if
	}// Of isEmpty
	
	/**
	 * ***********************
	 * The entrance of program.
	 * 
	 * @param  args
	 * 				Not used now.
	 * ***********************
	 */
	public static void main(String[] args) {
		ObjectStack tempObjectStack = new ObjectStack();
		
		for(int i = 0; i < 5; i++) {
			tempObjectStack.push(Integer.valueOf(i+10));
			tempObjectStack.push(i+10);
		}// Of for i
		System.out.println("The current stack is:" + tempObjectStack.toString());
		
		for(char ch = 'a'; ch < 'f'; ch++) {
			tempObjectStack.push(Character.valueOf(ch)); 
			//tempObjectStack.push(ch);
			//tempObjectStack.push(new Character(ch));
		}// Of for ch
		System.out.println("The current stack is:" + tempObjectStack.toString());	
	}// Of main
}// Of ObjectStack

25.2 对象栈运行结果

 25.3 中序遍历栈实现

/**
	 * ****************************
	 * In-order visit with stack.
	 * ****************************
	 */
	public void inOrderWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				tempStack.push(tempNode);
				tempNode = tempNode.leftChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				System.out.println("" + tempNode.value + "");
				tempNode = tempNode.rightChild; 
			}// Of if 				
		}// Of while 		
	}// Of inOrderWithStack

25.4 中序遍历栈实现运行结果

 Day 26: 深度遍历的栈实现(前序和后序)

后序遍历中,问题的等价转换思路,太神奇了!

26.1 代码实现

/**
	 * ****************************
	 * Pre-order visit with stack.
	 * ****************************
	 */
	public void preOrderWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				tempStack.push(tempNode);
				System.out.println("" + tempNode.value + "");
				tempNode = tempNode.leftChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				tempNode = tempNode.rightChild; 
			}// Of if 				
		}// Of while 		
	}// Of preOrderWithStack
	
	/**
	 * ****************************
	 * Post-order visit with stack.
	 * ****************************
	 */
	public void postOrderWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		ObjectStack tempOutputStack = new ObjectStack();
		
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				//Store for output.
				tempStack.push(tempNode);
				tempOutputStack.push(tempNode.value);
				tempNode = tempNode.rightChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				tempNode = tempNode.leftChild; 
			}// Of if 				
		}// Of while 	
		
		//Now reverse output.
		while (!tempOutputStack.isEmpty()) {
			System.out.println(" " + tempOutputStack.pop() + " ");
		}// Of while
	}// Of postOrderWithStack

26.2 运行结果

Day 27:Hanoi 问题

 在运行程序时,报错栈溢出,找了半天错误,原来是在结束条件时,忘记写return。

27.1 代码

package datastructure.tree;

/**
 * Hanoi tower.
 * @author XuQiong
 *
 */
public class Hanoi {
	
	/**
	 * **********************
	 * Move a number of plates.
	 * 
	 * @param paraSource
	 * 				The source pole.
	 * @param paraIntermedium
	 * 				The intermediary pole.
	 * @param paraDestination
	 * 				The destination pole.
	 * @param paraNumber
	 * 				The number of plates.
	 * **********************
	 */

	public static void hanoi(char paraSource, char paraIntermediary, char paraDestination,
			int paraNumber) {
		if(paraNumber == 1) {
			System.out.println(paraSource + " -> " + paraDestination);
			return;
		}// Of if 
		
		hanoi(paraSource, paraDestination, paraIntermediary, paraNumber - 1);
		System.out.println(paraSource + " -> " + paraDestination);
		hanoi(paraIntermediary, paraSource, paraDestination, paraNumber - 1);
	}// Of hanoi
	
	/**
	 * *************************
	 * The entrance of program.
	 * 
	 * @param args
	 * 				Not used now.
	 * *************************
	 */
	public static void main(String args[]) {
	    hanoi('a', 'b', 'c', 3);
	}// Of main
}// Of class Hanoi

27.2 运行结果

 Day 28: Huffman 编码(结点定义与文件读取)

1、异常处理,参考知乎  用不秃头的码农

两种方式:

  1. try/catch
  2. throws
  • public class ExceptionTest{
        public void readFile() {
            try {
                FileInputStream fileInputStream=new FileInputStream("xxx.text");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }finally {
            }
        }
    }
  • public class ExceptionTest{
        public void readFile() throws FileNotFoundException {
            FileInputStream fileInputStream=new FileInputStream("xxx.text");
        }
    }

  • 差异在于,try/catch捕获到异常后直接在catch语句里进行处理,处理完成之后程序继续往下执行。而throws则是将异常抛给它的上一级进行解决,程序就不再往下执行了。

使用catch捕获到异常之后,我们可以对异常进行处理,常见的方式就是将异常打印出来或者写入到日志里。下面是Throwable类中的常用方法。

public String getMessage() //返回异常的简要信息
public String getLocalizedMessage() //返回异常的本地化信息,默认和getMessage是一样的,如果要加入本地化信息往往是子类重写这个方法
public String toString() //返回异常的更详细信息
public void printStackTrace() //在控制台输出异常信息。

try/catch之后往往还会更finally语句,finally语句中的代码会在程序处理完成最后被执行,不管是否进入异常。如果在代码中有return语句,在return执行之前,finally语句中的代码会被先执行。 finally 语句的返回值将会覆盖原始的返回值。

Day 29: Huffman 编码  (建树)

29.1 代码

package datastructure.tree;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
 * Huffman tree, encoding, and decoding. For simplicity, only ASCII characters
 * are supported.
 * 
 * @author XuQiong
 */
public class Huffman {
	
	/**
	 * An inner class for Huffman nodes.
	 */
	class HuffmanNode {
		/**
		 * The char. Only valid for leaf nodes.
		 */
		char character;
		
		/**
		 * Weight. It can also be double.
		 */
		int weight;
		
		/**
		 * The left child.
		 */
		HuffmanNode leftChild;
		
		/**
		 * The right child.
		 */
		HuffmanNode rightChild;
		
		/**
		 * The parent. It helps constructing the huffman code of each character.
		 */
		HuffmanNode parent;
		
		/**
		 * ***************************
		 * The first constructor.
		 * ***************************
		 */
		public HuffmanNode(char paraCharacter, int paraWeight, HuffmanNode paraLeftChild, 
				HuffmanNode paraRightChild, HuffmanNode paraParent) {
			character = paraCharacter;
			weight = paraWeight;
			leftChild = paraLeftChild;
			rightChild = paraRightChild;
			parent = paraParent;			
		}// Of HuffmanNode
		
		/**
		 * ***************************
		 * To string.
		 * ***************************
		 */
		public String toString() {
			String resultString = "(" + character + ", " + weight + ")";
			return resultString;
		}// Of toString
	}// Of class HuffmanNode
	
    /**
     * The number of characters. 256 for ASCII.
     */
	public static final int NUM_CHARS = 256;
	
	/**
	 * The input text. It is stored in a string for simplicity.
	 */
	String inputText;
	
	/**
	 * The length of the alphabet, also the number of leaves.
	 */
	int alphabetLength;
	
	/**
	 * The alphabet;
	 */
	char[] alphabet;
	
	/**
	 * The count of chars. The length is 2 * alphabetLength - 1 to include
	 * non-leaf nodes.
	 */
	int[] charCounts;
	
	/**
	 * The mapping of chars to the indices in the alphabet.
	 */
	int[] charMapping;
	
	/**
	 * Codes for each char in the alphabet. It should have the same length as 
	 * alphabet.
	 */
	String[] huffmanCodes;
	
	/**
	 * All nodes. The last node is the root.
	 */
	HuffmanNode[] nodes;
	
	/**
	 * ***************************
	 * The first constructor.
	 * 
	 * @param paraFilename.
	 * 				The text filename.
	 * ***************************
	 */
	public Huffman(String paraFilename) {
		charMapping = new int[NUM_CHARS];
		
		readText(paraFilename);
	}
	
	/**
	 * ****************************
	 * Read text.
	 * 
	 * @param paraFilename
	 * 				The text filename.
	 * ****************************
	 */
	public void readText(String paraFilename) {
		try {
			inputText = Files.newBufferedReader(Paths.get(paraFilename), StandardCharsets.UTF_8)
					.lines().collect(Collectors.joining("\n"));
		} catch (Exception ee) {
			System.out.println(ee);
			System.exit(0);
		}// Of try
		
		System.out.println("The text is: \r\n" + inputText);
	}// Of readText
	
	/**
	 * ******************************
	 * Construct the alphabet. The results are stored in the member variables
	 * charMapping and alphabet.
	 * ******************************
	 */
	public void constructAlphabet() {
		//Initialize.
		Arrays.fill(charMapping, -1);
		
		//The count for each char. At most NUM_CHARS chars.
		int[] tempCharCounts = new int[NUM_CHARS];
		
		//The index of the char in the ASCII charset.
		int tempCharIndex;
		
		//Step 1. Scan the string to obtain the counts.
		char tempChar;
		for (int i = 0; i < inputText.length(); i++) {
			tempChar = inputText.charAt(i);
			tempCharIndex = (int)tempChar;
			
			System.out.println("" + tempCharIndex + "");
			
			tempCharCounts[tempCharIndex]++;
		} // Of for i
		
		//Step 2. Scan to determine the size of alphabet.
		alphabetLength = 0;
		for (int i = 0; i < 255; i++) {
			if(tempCharCounts[i] > 0) {
				alphabetLength++;
			}// Of if
		}// Of for i
		
		//Step 3. Compress to the alphabet.
		alphabet = new char[alphabetLength];
		charCounts = new int[2 * alphabetLength - 1];
		
		int tempCounter = 0;
		for (int i = 0; i < NUM_CHARS; i++) {
			if(tempCharCounts[i] > 0) {
				alphabet[tempCounter] = (char) i;
				charCounts[tempCounter] = tempCharCounts[i];
				charMapping[i] = tempCounter;
				tempCounter++;
			}// Of if;
		}// Of for i;
		
		System.out.println("The alphabet is: " + Arrays.toString(alphabet));
		System.out.println("Their counts are: " + Arrays.toString(charCounts));
		System.out.println("The char mapping are: " + Arrays.toString(charMapping));
	}// Of contructAlphabet
	
	/**
	 * *****************************
	 * Construct the tree.
	 * *****************************
	 */
	public void constructTree() {
		//Step 1. Allocate space.
		nodes = new HuffmanNode[alphabetLength * 2 - 1];
		boolean[] tempProcessed = new boolean[alphabetLength * 2 - 1];
		
		//Step 2. Initialize leaves.
		for (int i = 0; i < alphabetLength; i++) {
			nodes[i] = new HuffmanNode(alphabet[i], charCounts[i], null, null, null);
		}// Of ofr i
		
		//Step 3. Construct the tree.
		int tempLeft, tempRight, tempMinimal;
		for(int i = alphabetLength; i < 2* alphabetLength; i++) {
			//Step 3.1 Select the first minimal as the left Child.
			tempLeft = -1;
			tempMinimal = Integer.MAX_VALUE;
			for (int j = 0; j < i; j++) {
				if(tempProcessed[j]) {
					continue;
				}// Of if
			}// Of for j
			tempProcessed[tempLeft] = true;
			
			//Step 3.2 Select the second minimal as the right child.
			tempRight = -1;
			tempMinimal = Integer.MAX_VALUE;
			for(int j = 0; j < i; j++) {
				if(tempProcessed[j]) {
					continue;
				}// Of if
				
				if(tempMinimal > charCounts[j]) {
					tempMinimal = charCounts[j];
					tempRight = j;
				}// Of if 
			}// Of for j
			tempProcessed[tempRight] = true;
			System.out.println("Selecting " + tempLeft + " and" + tempRight);
			
			//Step 3.3 Construct the new node.
			charCounts[i] = charCounts[tempLeft] + charCounts[tempRight];
			nodes[i] = new HuffmanNode('*', charCounts[i], nodes[tempLeft], nodes[tempRight], null);
			
			//Step 3.4 Link with children.
			nodes[tempLeft].parent = nodes[i];
			nodes[tempRight].parent = nodes[i];
			System.out.println("The children of " + i + "are " + tempLeft + " and " + tempRight);
		} // Of for i
	}// Of constructTree
	
	
	/**
	 * ******************************
	 * Get the root of the binary tree.
	 * 
	 * @return The root.
	 * ******************************
	 */
	public HuffmanNode getRoot() {
		return nodes[nodes.length - 1];
	}// Of getRoot
	
	
	
	/**
	 * ******************************
	 * The entrance of program.
	 * 
	 * @param args
	 * 				Not used now.
	 * ******************************
	 */
	public static void main(String args[]) {
		Huffman tempHuffman = new Huffman("E:/Java/Java_sampledata/huffmantext.txt");
		tempHuffman.constructAlphabet();
	    
		tempHuffman.constructTree();
	}// Of main
}// Of class Huffman

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值