20182327 2019-2020 《程序设计与数据结构》哈夫曼编码测试报告
2019-11-22 10:00 BBIowa 阅读(379) 评论(0) 编辑 收藏 举报20182327 2019-2020 《程序设计与数据结构》哈夫曼编码测试报告
- 课程:《程序设计与数据结构》
- 班级: 1823
- 姓名:赵天昊
- 学号:20182327
- 实验教师:王志强
- 实验日期:2019年11月17日
- 必修/选修: 必修
教材中的哈夫曼树
-
1、在计算机数据处理中,哈夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。
-
2、例如,在英文中,e的出现机率最高,而z的出现概率则最低。当利用哈夫曼编码对一篇英文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26)。用普通的表示方法时,每个英文字母均占用一个字节,即8个比特。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。
-
3、哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1XL1+W2XL2+W3XL3+...+WnXLn),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明哈夫曼树的WPL是最小的。
哈夫曼树及测试的实现
-
参考教材java创建哈夫曼树和实现哈夫曼——java实现哈夫曼编码,尝试读懂代码的同时加入自己的理解。
-
首先建立哈夫曼树的结点类【HuffmanNode】利用泛型实现结点,定义左子树,右子树,权值和编码。
public class HuffmanTreeNode implements Comparable<HuffmanTreeNode>{ protected int weight; // 权值 protected HuffmanTreeNode left; // 左孩子 protected HuffmanTreeNode right; // 右孩子 protected HuffmanTreeNode parent; // 父结点 protected char element; protected HuffmanTreeNode(int weight, char element, HuffmanTreeNode left, HuffmanTreeNode right, HuffmanTreeNode parent) { this.weight = weight; this.element = element; this.left = left; this.right = right; this.parent = parent; } @Override public int compareTo(HuffmanTreeNode o) { if (this.weight > o.weight) return 1; else if (this.weight < o.weight) return -1; else return 0; }
···
-
编写以下代码读取txt文件中的字母,用于将字母转化成哈夫曼编码。
public static void main(String[] args) throws IOException { File file = new File("C:\\Users\\12441\\Desktop\\game\\input1.txt"); Scanner scan = new Scanner(file); String s = scan.nextLine(); System.out.println(s); int[] array = new int[26]; for (int i = 0; i < array.length; i++) { array[i] = 0; } for (int i = 0; i < s.length(); i++) { char x = s.charAt(i); array[x - 'a']++;
···
- 编写【getEnCoding】类将读取的字母转化成为哈夫曼编码,并且规定左子树为0,右子树为1
public String[] getEncoding() {
ArrayList<HuffmanTreeNode> arrayList = new ArrayList();
inOrder(root,arrayList);
for (int i=0;i<arrayList.size();i++)
{
HuffmanTreeNode node = arrayList.get(i);
String result ="";
int x = node.element-'a';
Stack stack = new Stack();
while (node!=root)
{
if (node==node.parent.left)
stack.push(0);
if (node==node.parent.right)
stack.push(1);
node=node.parent;
}
while (!stack.isEmpty())
{
result +=stack.pop();
}
codes[x] = result;
}
return codes;
}
public HuffmanTreeNode getRoot() {
return root;
}
- 最后编写实现类【Huffman】从input1.txt中读取信息,转化为哈夫曼编码后将哈夫曼编码放入output.txt中后完成测试
public class RunHuffmanTree {
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\12441\\Desktop\\game\\input1.txt");
Scanner scan = new Scanner(file);
String s = scan.nextLine();
System.out.println(s);
int[] array = new int[26];
for (int i = 0; i < array.length; i++) {
array[i] = 0;
}
for (int i = 0; i < s.length(); i++) {
char x = s.charAt(i);
array[x - 'a']++;
}
System.out.println("打印各字母出现频率:");
for (int i = 0; i < array.length; i++) {
System.out.print((char) ('a' + i) + ":" + (double) array[i] / s.length() + " ");
}
HuffmanTreeNode[] huffmanTreeNodes = new HuffmanTreeNode[array.length];
for (int i = 0; i < array.length; i++) {
huffmanTreeNodes[i] = new HuffmanTreeNode(array[i], (char) ('a' + i), null, null, null);
}
HuffmanTree huffmanTree = new HuffmanTree(huffmanTreeNodes);
System.out.println("打印各字母的编码");
String[] codes = huffmanTree.getEncoding();
for (int i = 0; i < codes.length; i++) {
System.out.println((char) ('a' + i) + ":" + codes[i]);
}
//进行编码:
String result = "";
for (int i = 0; i < s.length(); i++) {
int x = s.charAt(i) - 'a';
result += codes[x];
}
System.out.println("编码结果:" + result);
//写入文件
File file1 = new File("C:\\Users\\12441\\Desktop\\game\\output.txt");
FileWriter fileWriter = new FileWriter(file1);
fileWriter.write(result);
fileWriter.close();
//从文件读取
Scanner scan1 = new Scanner(file1);
String s1 = scan1.nextLine();
HuffmanTreeNode huffmanTreeNode = huffmanTree.getRoot();
//进行解码
String result2 = "";
for (int i = 0; i < s1.length(); i++) {
if (s1.charAt(i) == '0') {
if (huffmanTreeNode.left != null) {
huffmanTreeNode = huffmanTreeNode.left;
}
} else {
if (s1.charAt(i) == '1') {
if (huffmanTreeNode.right != null) {
huffmanTreeNode = huffmanTreeNode.right;
}
}
}
if (huffmanTreeNode.left == null && huffmanTreeNode.right == null) {
result2 += huffmanTreeNode.element;
huffmanTreeNode = huffmanTree.getRoot();
}
}
System.out.println("解码结果:" + result2);
//写入文件
File file2 = new File("C:\\Users\\12441\\Desktop\\game\\file2.txt");
FileWriter fileWriter1 = new FileWriter(file1);
fileWriter1.write(result2);
// 判断解码后原来是否一致
System.out.println("编码解码后原来是否一致:" + result2.equals(s));
}
}