Java学习日记(21-30天,树与二叉树)

学习地址

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

二叉树是一种重要的树形结构,二叉树特点是每个结点最多只能有两棵子树,且有左右之分。
一个二叉树的结点有数据域、左孩子域、右孩子域。

public My(char paraName) {
	value = paraName;
	leftChild = null;
	rightChild = null;
}

手动建立一个二叉树:

public static My manualConstructTree() {
	My resultTree = new My('a');
	My tempTreeB = new My('b');
	My tempTreeC = new My('c');
	My tempTreeD = new My('d');
	My tempTreeE = new My('e');
	My tempTreeF = new My('f');
	My tempTreeG = new My('g');

	resultTree.leftChild = tempTreeB;
	resultTree.rightChild = tempTreeC;
	tempTreeB.rightChild = tempTreeD;
	tempTreeC.leftChild = tempTreeE;
	tempTreeD.leftChild = tempTreeF;
	tempTreeD.rightChild = tempTreeG;

	return resultTree;
}

建立后的二叉树如图所示:(深度为4,结点数为7)
二叉树
使用递归的方法遍历二叉树

先序遍历:根左右,先访问根结点,然后左结点、右结点。先序遍历的结果 a b d f g c e

public void preOrderVisit() {
	System.out.print("" + value + " ");
	if (leftChild != null) {
		leftChild.preOrderVisit();
	}
	if (rightChild != null) {
		rightChild.preOrderVisit();
	}
}

中序遍历:左根右,先访问左结点,再访问根结点,最后访问右结点。中序遍历的结果 b f d g a e c

public void inOrderVisit() {
	if (leftChild != null) {
		leftChild.inOrderVisit();
	}
	System.out.print("" + value + " ");
	if (rightChild != null) {
		rightChild.inOrderVisit();
	}
}

后序遍历:左右根,先访问左结点、右结点,最后访问根结点。后序遍历的结果 f g d b e c a

public void postOrderVisit() {
	if (leftChild != null) {
		leftChild.postOrderVisit();
	}
	if (rightChild != null) {
		rightChild.postOrderVisit();
	}
	System.out.print("" + value + " ");
}

计算二叉树的深度:先计算左子树的深度,再计算右子树的深度,当访问到叶子结点时返回深度1,如果左子树比右子树深则返回左子树深度+1,否则返回右子树深度+1.

public int getDepth() {
	if ((leftChild == null) && (rightChild == null)) {
		return 1;
	}
	int tempLeftDepth = 0,tempRightDepth = 0;
	if (leftChild != null) {
		tempLeftDepth = leftChild.getDepth();
	}
	if (rightChild != null) {
		tempRightDepth = rightChild.getDepth();
	}

	if (tempLeftDepth >= tempRightDepth) {
		return tempLeftDepth + 1;
	} else {
		return tempRightDepth + 1;
	} 
}

计算二叉树的结点数:和计算深度原理一样,先计算左子树的结点数,再计算右子树的结点数,最后返回左子树的结点加右子树的结点加1(表示当前结点),访问到叶子结点时,返回结点数1。

public int getNumNodes() {
	if ((leftChild == null) && (rightChild == null)) {
		return 1;
	}

	int tempLeftNodes = 0,tempRightNodes = 0;
	if (leftChild != null) {
		tempLeftNodes = leftChild.getNumNodes();
	}
	if (rightChild != null) {
		tempRightNodes = rightChild.getNumNodes();
	} 

	return tempLeftNodes + tempRightNodes + 1;
}

22.二叉树的存储

从完全满二叉树的广度优先遍历(bfs)角度来考虑这个问题: 每个节点都有一个 data 及其在二叉树中的位置.令根节点的位置为 0; 则第 2 层节点的位置依次为 1 至 2; 第 3 层节点的位置依次为 3 至 6. 以此类推.

在第21天的树中: 空树使用 0 来表示, 可以用一个向量来存储: [a, b, c, 0, d, e, 0, 0, 0, f, g]
优点: 仅需要一个向量, 简单直接.
缺点: 对于实际的二叉树, 很多子树为空, 导致大量的 0 值.

刘知鑫指出: 应使用压缩存储方式, 即将节点的位置和值均存储.
可表示为两个向量:
[0, 1, 2, 4, 5, 9, 10]
[a, b, c, d, e, f, g]

使用两个队列(队列参考第18天代码)来对二叉树进行层次遍历,分别存储二叉树结点的位置与值:
将二叉树从根结点开始依此入队,左子树的下标为父结点下标×2+1,右子树的下标为父结点下标×2+2.

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);
	}

	if (tempTree.rightChild != null) {
		tempQueue.enqueue(tempTree.rightChild);
		tempIntQueue.enqueue(tempIndex * 2 + 2);
	}

	tempTree = (BinaryCharTree) tempQueue.dequeue();
	tempIndex = tempIntQueue.dequeue();
}

运行结果:
在这里插入图片描述

23.使用通用性的队列

1、Object类是所有Java类的根基类(父类),如果在类的声明中未使用extends关键字指明其基类,则默认基类是Object类。

2、存储对象,实际上是存储对象的地址 (引用、指针),因此,可以存储任何类的对象 (的引用)。

3、可以通过强制类型转换将对象转成其本身的类别,例如程序中:括号中表示将出队的数据转换为BinaryCharTree类的数据。

CircleObjectQueue tempQueue = new CircleObjectQueue();
tempQueue.enqueue(this);
BinaryCharTree tempTree = (BinaryCharTree) tempQueue.dequeue();

4、括号中的类型即表示强制类型转换。Java将 int, double, char 分别封装到 Integer, Double, Char 类。

代码:

public class CircleObjectQueue {
	public static void main(String args[]) {
		CircleObjectQueue tempQueue = new CircleObjectQueue();
	}

	public static final int TOTAL_SPACE = 10;

	Object[] data;
	int head;
	int tail;

	public CircleObjectQueue() {
		data = new Object[TOTAL_SPACE];
		head = 0;
		tail = 0;
	}

	public void enqueue(Object paraValue) {
		if ((tail + 1) % TOTAL_SPACE == head) {
			System.out.println("Queue full.");
			return;
		}
		data[tail % TOTAL_SPACE] = paraValue;
		tail++;
	}

	public Object dequeue() {
		if (head == tail) {
			return null;
		}

		Object resultValue = data[head];

		head++;

		return resultValue;
	}

	public String toString() {
		String resultString = "";

		if (head == tail) {
			return "empty";
		}

		for (int i = head; i < tail; i++) {
			resultString += data[i % TOTAL_SPACE] + ", ";
		}

		return resultString;
	}
}
public void toDataArraysObjectQueue() {
	int tempLength = getNumNodes();

	valuesArray = new char[tempLength];
	indicesArray = new int[tempLength];
	int i = 0;

	CircleObjectQueue tempQueue = new CircleObjectQueue();
	tempQueue.enqueue(this);
	CircleObjectQueue tempIntQueue = new CircleObjectQueue();
	Integer tempIndexInteger = new Integer(0);
	tempIntQueue.enqueue(tempIndexInteger);

	BinaryCharTree tempTree = (BinaryCharTree) tempQueue.dequeue();
	int tempIndex = ((Integer) tempIntQueue.dequeue()).intValue();
	System.out.println("tempIndex = " + tempIndex);
	while (tempTree != null) {
		valuesArray[i] = tempTree.value;
		indicesArray[i] = tempIndex;
		i++;

		if (tempTree.leftChild != null) {
			tempQueue.enqueue(tempTree.leftChild);
			tempIntQueue.enqueue(new Integer(tempIndex * 2 + 1));
		}

		if (tempTree.rightChild != null) {
			tempQueue.enqueue(tempTree.rightChild);
			tempIntQueue.enqueue(new Integer(tempIndex * 2 + 2));
		}

		tempTree = (BinaryCharTree) tempQueue.dequeue();
		if (tempTree == null) {
			break;
		}
		
		tempIndex = ((Integer) tempIntQueue.dequeue()).intValue();
	}
}

24.二叉树的建立

在第22天的基础上增加了一种二叉树的构造方法,是相反的过程。先用一个线性表存储所有结点,再连接相应的结点,最后把线性表中第一个结点作为根结点。

核心代码:
遍历所有结点,如果i结点的下标等于j结点下标×2+1,则j为i的左结点,如果i结点的下标等于j结点下标×2+2,则j为i的右结点。

for (int i = 1; i < tempNumNodes; i++) {
	for (int j = 0; j < i; j++) {
		System.out.println("indices " + paraIndicesArray[j] + " vs. " + paraIndicesArray[i]);
		if (paraIndicesArray[i] == paraIndicesArray[j] * 2 + 1) {
			tempAllNodes[j].leftChild = tempAllNodes[i];
			System.out.println("Linking " + j + " with " + i);
			break;
		} else if (paraIndicesArray[i] == paraIndicesArray[j] * 2 + 2) {
			tempAllNodes[j].rightChild = tempAllNodes[i];
			System.out.println("Linking " + j + " with " + i);
			break;
		}
	}
}

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

25.1具有通用性的对象栈

修改第十四天栈的代码,将char改为通用的object。

int depth;
Object[] data;

public ObjectStack() {
	depth = 0;
	data = new Object[MAX_DEPTH];
}

增加了判断栈是否为空(栈深度为0时栈空)的代码:

public boolean isEmpty() {
	if (depth == 0) {
		return true;
	}

	return false;
}

用强制类型转换:

for (char ch = 'a'; ch < 'm'; ch++) {
	tempStack.push(new Character(ch));
	System.out.println("The current stack is: " + tempStack);
}

char tempChar;
for (int i = 0; i < 12; i++) {
	tempChar = ((Character)tempStack.pop()).charValue();
	System.out.println("Poped: " + tempChar);
	System.out.println("The current stack is: " + tempStack);
}

25.2中序遍历

利用栈来实现二叉树的中序遍历:
如果栈不为空并且结点有数据,那么该结点入栈,访问该结点,然后访问他的左结点,直到已没有左结点(即tempNode==null时),将栈顶出栈(就是二叉树最左边的结点),输出结点的值,然后再访问该结点的右结点。

public void inOrderVisitWithStack() {
	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.print("" + tempNode.value + " ");
			tempNode = tempNode.rightChild;
		}
	}
}

二叉树:

char[] tempCharArray = { ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’ };
int[] tempIndicesArray = { 0, 1, 2, 4, 5, 12 };
二叉树

中序遍历结果为:B D A E F C

26.二叉树深度遍历的栈实现 (前序和后序)

前序遍历:
前序就是输出结点的语句位置和中序不一样,因为前序是先访问根结点,所以一访问结点就要输出,中序是先访问左结点,所以当访问到最左边的结点时再出栈输出结点。
前序遍历结果:A B D C E F

public void preOrderVisitWithStack() {
	ObjectStack tempStack = new ObjectStack();
	BinaryCharTree tempNode = this;
	while (!tempStack.isEmpty() || tempNode != null) {
		if (tempNode != null) {
			System.out.print("" + tempNode.value + " ");
			tempStack.push(tempNode);
			tempNode = tempNode.leftChild;
		} else {
			tempNode = (BinaryCharTree) tempStack.pop();
			tempNode = tempNode.rightChild;
		}
	}
}

后续遍历:
在二叉树中有六种遍历排列
1.左中右—中序
2.左右中—后序
3.中左右—前序
4.右中左
5.右左中
6.中右左
在前序遍历的基础上,将左右子树互换,便得到第6种排列,然后再将其倒序,就可以得到后序遍历了。
再申请一个栈来存储第六种排列,然后将其倒序输出

代码:与前序相同,只不过把输出语句换成将结点数据入栈。
后序遍历结果:D B F E C A

public void postOrderVisitWithStack() {
	ObjectStack tempStack = new ObjectStack();
	BinaryCharTree tempNode = this;
	ObjectStack tempOutputStack = new ObjectStack();
	
	while (!tempStack.isEmpty() || tempNode != null) {
		if (tempNode != null) {
			tempOutputStack.push(new Character(tempNode.value));
			tempStack.push(tempNode);
			tempNode = tempNode.rightChild;
		} else {
			tempNode = (BinaryCharTree) tempStack.pop();
			tempNode = tempNode.leftChild;
		}
	}
	
	while (!tempOutputStack.isEmpty()) {
		System.out.print("" + tempOutputStack.pop() + " ");
	}
}

27.Hanoi 塔问题

汉诺塔问题分析:
先用一个动图展示下汉诺塔的移动过程:

汉诺塔
我们分情况讨论一下盘子的移动:

情况一:
当盘子只有1个(调用 hanoi(1,A,B,C))
盘子只有一个的时候,只要直接将盘子从开始柱移动到目标柱就可以了,并没有中间状态(即不用借助中转柱),在hanoi方法中可以用一句话表示该移动动作:

System.out.println(A -> C);

情况二:
当盘子有2个(调用 hanoi(A,B,C,2))这个情况分三个步骤进行:

step1. 把除了最大的盘子之外的盘子从A移到B
A—>B (开始柱—>中转柱) 【相当于调用 hanoi(A,C,B,1)】
step2. 把最大的盘子从A移到C
A—>C (开始柱—>目标柱) 【相当于调用 hanoi(A,B,C,1)】
step3. 把除了最大的盘子之外的盘子从B移到C
B—>C (中转柱—>目标柱) 【相当于调用 hanoi(B,A,C,1)】

情况三:
有3个盘子(调用 hanoi(A,B,C,3))
分三步进行:

step1. 把除了最大的盘子之外的盘子从A移到B(注意对于这个步骤来说此时A为开始柱,C为中转柱,B为目标柱,这样才能完成把最上面的2个盘子从A—>B的任务)
A—>C (开始柱—>中转柱) 【相当于调用 hanoi(A,B,C,1)】
A—>B (开始柱—>目标柱) 【相当于调用 hanoi(A,C,B,1)】
C—>B (中转柱—>目标柱) 【相当于调用 hanoi(C,A,B,1)】

step2. 把最大的盘子从A移到C(对于这个步骤来说此时A为开始柱,B为中转柱,C为目标柱,这样才能把最大的盘子从A—>C)
A—>C (开始柱—>目标柱) 【相当于调用 move(A,B,C,1),即直接执行 print(‘A—>C’)】

step3. 把除了最大的盘子之外的盘子从B移到C(注意对于这个步骤来说此时B为开始柱,A为中转柱,C为目标柱,这样才能完成把处于step2中的中转柱的2个盘子从B—>C的任务)
B —> A (开始柱—>中转柱) 【相当于调用 hanoi(B,C,A,1)】
B —> C (开始柱—>目标柱) 【相当于调用 hanoi(B,A,C,1)】
A —> C (中转柱—>目标柱) 【相当于调用 hanoi(A,B,C,1)】

情况三的step1和step3的形式和整个情况二的形式很像,要注意到分析的层次不相同时,开始柱,中转柱,目标柱是不一样的。对于step1来说中转柱是C,对于step3来说中转柱是A,对于整个情况三来说中转柱是B。

前面我们已经确定了情况二调用的函数是 hanoi(A,B,C,2),其等价于
A—>B
A—>C
B—>C
然后情况三的step1是
A—>C
A—>B
C—>B
跟情况二的形式是一样的,根据前面情况二的转化,那这三步就可以转化成函数 hanoi(A,C,B,2)
情况三的step3同理,做转化就成了函数 hanoi(B,A,C,2)
而情况三的step2可以直接用一句 println(A -> C) 来代替 hanoi(A,B,C,1)

所以整个情况三就可以这样来表示:
hanoi(A,C,B,2) //step1. 把除了最大的盘子之外的盘子从A移到B
println(A -> C) //step2. 把最大的盘子从A移到C
hanoi(B,A,C,2) //step3. 把除了最大的盘子之外的盘子从B移到C

以上三行代码又等价于函数 hanoi(A,B,C,3)

整体代码:

package xjx;

public class Hanoi {
	public static void main(String args[]) {
		hanoi('a', 'b', 'c', 3);
	}
	
	public static void hanoi(char paraSource, char paraIntermediary, char paraDestination, int paraNumber) {
		if (paraNumber == 1) {
			System.out.println(paraSource + "->" + paraDestination + " ");
			return;
		}

		hanoi(paraSource, paraDestination, paraIntermediary, paraNumber - 1);
		System.out.println(paraSource + "->" + paraDestination + " ");
		hanoi(paraIntermediary, paraSource, paraDestination, paraNumber - 1);
	}
}

移动过程:
在这里插入图片描述

28.Huffman 编码 (节点定义与文件读取)

哈夫曼树, 即带权路径最小的树, 权值最小的结点远离根结点, 权值越大的结点越靠近根结点。哈夫曼树也叫最优二叉树。

哈夫曼树编码:
左孩子路径编码为0,右孩子路径编码为1
如图:
哈夫曼树

A 的编码: 0
D 的编码: 10
B 的编码: 110
C 的编码: 111

如果考虑到进一步节省存储空间,就应该将出现概率大(占比多)的字符用尽量少的0-1进行编码,也就是更靠近根(节点少),这也就是最优二叉树—哈夫曼树。

权值大的在上层,权值小的在下层。满足出现频率高的码长短。

哈夫曼编码的带权路径权值:叶子节点的值 * 叶子节点的高度(根节点为0)

哈夫曼树的节点定义与文件读取:

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

public class Huffman {

	//节点定义
	class HuffmanNode {
		char character;
		int weight;
		HuffmanNode leftChild;
		HuffmanNode rightChild;
		HuffmanNode parent;

		public HuffmanNode(char paraCharacter, int paraWeight, HuffmanNode paraLeftChild,
				HuffmanNode paraRightChild, HuffmanNode paraParent) {
			character = paraCharacter;
			weight = paraWeight;
			leftChild = paraLeftChild;
			rightChild = paraRightChild;
			parent = paraParent;
		}
		
		public String toString() {
			String resultString = "(" + character + ", " + weight + ")";

			return resultString;
		}

	}

	public static final int NUM_CHARS = 256;
	//存储文件的字符串
	String inputText;
	//叶子节点数
	int alphabetLength;
	char[] alphabet;
	//哈夫曼树总结点数 2*alphabetLength-1
	int[] charCounts;
	int[] charMapping;
	//哈夫曼树结点
	String[] huffmanCodes;
	HuffmanNode[] nodes;

	public Huffman(String paraFilename) {
		charMapping = new int[NUM_CHARS];

		readText(paraFilename);
	}
	
	//文件读取
	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);
		}

		System.out.println("The text is:\r\n" + inputText);
	}
}

29.Huffman 编码 (建树)

建立哈夫曼树是一个自底向上的过程,从最小的开始选择,最后生成的结点是根结点。

例如:将3、5、7、9这四个数字建立一个哈夫曼树,先选择3和5分别作为一个新结点的左孩子和右孩子,生成的新结点权值为8,然后选择7和8再作为一个新结点的左孩子和右孩子,新结点权值为15,最后选择9和15。
生成的哈夫曼树如图:
哈夫曼树

建立哈夫曼树过程的代码:

public void constructAlphabet() {
	Arrays.fill(charMapping, -1);

	int[] tempCharCounts = new int[NUM_CHARS];
	int tempCharIndex;

	//计算字符个数
	char tempChar;
	for (int i = 0; i < inputText.length(); i++) {
		tempChar = inputText.charAt(i);
		tempCharIndex = (int) tempChar;

		System.out.print("" + tempCharIndex + " ");

		tempCharCounts[tempCharIndex]++;
	}

	//计算叶子节点数
	alphabetLength = 0;
	for (int i = 0; i < 255; i++) {
		if (tempCharCounts[i] > 0) {
			alphabetLength++;
		}
	} 

	//将字符存入数组
	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++;
		}
	}

	System.out.println("The alphabet is: " + Arrays.toString(alphabet));
	System.out.println("Their counts are: " + Arrays.toString(charCounts));
	System.out.println("The char mappings are: " + Arrays.toString(charMapping));
}

public void constructTree() {
	//申请空间
	nodes = new HuffmanNode[alphabetLength * 2 - 1];
	boolean[] tempProcessed = new boolean[alphabetLength * 2 - 1];

	//初始化叶子结点
	for (int i = 0; i < alphabetLength; i++) {
		nodes[i] = new HuffmanNode(alphabet[i], charCounts[i], null, null, null);
	}

	//建树
	int tempLeft, tempRight, tempMinimal;
	for (int i = alphabetLength; i < 2 * alphabetLength - 1; i++) {
		//选择第一小的作为左孩子
		tempLeft = -1;
		tempMinimal = Integer.MAX_VALUE;
		for (int j = 0; j < i; j++) {
			if (tempProcessed[j]) {
				continue;
			}
			if (tempMinimal > charCounts[j]) {
				tempMinimal = charCounts[j];
				tempLeft = j;
			}
		}
		tempProcessed[tempLeft] = true;

		//选择第二小的作为右孩子
		tempRight = -1;
		tempMinimal = Integer.MAX_VALUE;
		for (int j = 0; j < i; j++) {
			if (tempProcessed[j]) {
				continue;
			}
			if (tempMinimal > charCounts[j]) {
				tempMinimal = charCounts[j];
				tempRight = j;
			}
		}
		tempProcessed[tempRight] = true;
		System.out.println("Selecting " + tempLeft + " and " + tempRight);

		//创建新结点
		charCounts[i] = charCounts[tempLeft] + charCounts[tempRight];
		nodes[i] = new HuffmanNode('*', charCounts[i], nodes[tempLeft], nodes[tempRight], null);

		//连接自己的左孩子、右孩子结点
		nodes[tempLeft].parent = nodes[i];
		nodes[tempRight].parent = nodes[i];
		System.out.println("The children of " + i + " are " + tempLeft + " and " + tempRight);
	}
}

public HuffmanNode getRoot() {
	return nodes[nodes.length - 1];
}

30.Huffman 编码 (编码与解码)

接前两天的代码。
编码是从哈夫曼树的叶节点到根节点, 解码就是反过来。
编码在第28天已经讲到了,就是左子树分支为0右子树分支为1依此编码
解码就是输出对应的01串的的字符

public void preOrderVisit(HuffmanNode paraNode) {
	System.out.print("(" + paraNode.character + ", " + paraNode.weight + ") ");
	if (paraNode.leftChild != null) {
		preOrderVisit(paraNode.leftChild);
	}
	if (paraNode.rightChild != null) {
		preOrderVisit(paraNode.rightChild);
	} 
}

public void generateCodes() {
	huffmanCodes = new String[alphabetLength];
	HuffmanNode tempNode;
	for (int i = 0; i < alphabetLength; i++) {
		tempNode = nodes[i];
		String tempCharCode = "";
		while (tempNode.parent != null) {
			if (tempNode == tempNode.parent.leftChild) {
				tempCharCode = "0" + tempCharCode;
			} else {
				tempCharCode = "1" + tempCharCode;
			}

			tempNode = tempNode.parent;
		}
		huffmanCodes[i] = tempCharCode;
		System.out.println("The code of " + alphabet[i] + " is " + tempCharCode);
	}
}

public String coding(String paraString) {
	String resultCodeString = "";

	int tempIndex;
	for (int i = 0; i < paraString.length(); i++) {
		tempIndex = charMapping[(int) paraString.charAt(i)];
		resultCodeString += huffmanCodes[tempIndex];
	}
	return resultCodeString;
}

public String decoding(String paraString) {
	String resultCodeString = "";
	HuffmanNode tempNode = getRoot();

	for (int i = 0; i < paraString.length(); i++) {
		if (paraString.charAt(i) == '0') {
			tempNode = tempNode.leftChild;
			System.out.println(tempNode);
		} else {
			tempNode = tempNode.rightChild;
			System.out.println(tempNode);
		}
		if (tempNode.leftChild == null) {
			System.out.println("Decode one:" + tempNode);
			resultCodeString += tempNode.character;

			tempNode = getRoot();
		}
	}

	return resultCodeString;
}

public static void main(String args[]) {
	Huffman tempHuffman = new Huffman("D:/");
	
	tempHuffman.constructAlphabet();
	tempHuffman.constructTree();

	HuffmanNode tempRoot = tempHuffman.getRoot();
	System.out.println("The root is: " + tempRoot);
	System.out.println("Preorder visit:");
	tempHuffman.preOrderVisit(tempHuffman.getRoot());

	tempHuffman.generateCodes();

	String tempCoded = tempHuffman.coding("abcdb");
	System.out.println("Coded: " + tempCoded);
	String tempDecoded = tempHuffman.decoding(tempCoded);
	System.out.println("Decoded: " + tempDecoded);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值