20172332 2017-2018-2 《程序设计与数据结构》Java哈夫曼编码实验--哈夫曼树的建立,编码与解码
20172332 2017-2018-2 《程序设计与数据结构》Java哈夫曼编码实验--哈夫曼树的建立,编码与解码
哈夫曼树
- 1、路径和路径长度
- 在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
- 2、结点的权及带权路径长度
- 若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
- 3、树的带权路径长度
- 树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。
哈夫曼编码
- 问题概述:
在数据传输中,需要将传输的文字换成二进制的字符,用0和1的不同排列来表示字符。然而,在传送报文的时候总希望传输报文的总长度尽可能短。在实际的应用中,各个字符的出现频率或使用次数是不同的,在设计编码时,应使用频率高的用短码,使用频率低的用长码。 - 基本思路
对于数据通信中的报文编码问题,一般采用以下三步来解决:
统计每个报文的出现次数;
以报文字符为叶结点,以字符出现的次数为权重,构造哈夫曼树;
遍历二叉树,求报文字符编码及报文传输长度。
注意:在求文字符编码的时候,假设到每棵左子树的根结点的边为0,到右子树的结点的边为1。
哈夫曼树结点的结构
- 可以用一个数组存放原来的n个叶子结点和构造过程中临时生成的结点,数组大小为2n-1。所以,哈夫曼树类中有两个成员字段:data数组用于存放结点集合;leafNum表示哈夫曼树叶子结点的数目。而哈夫曼树结点一共有5个域:
关键代码与解读
- Node类:要实现Comparable接口,比较权重,好确定放的位置(编码是0还是1)。
public class Node<T> implements Comparable<Node<T>> {
@Override
//确定位置
public int compareTo(Node<T> other) {
if(other.getWeight() > this.getWeight()){
return 1;
}
if(other.getWeight() < this.getWeight()){
return -1;
}
return 0;
}
}
- HuffmanTree类:创建树,当还有结点时,对结点进行排序,然后左孩子为数组中的个数-2的结点,右孩子为数组中的个数-1的结点(用数组实现树的那一章说过左右孩子在数组中的索引),赋予左孩子的编码为0,右孩子的编码为1,双亲结点则为左右孩子相加的权重(也就是左右孩子的概率和),把双亲结点加入链表中,从链表中把旧的左右孩子删除,直至链表中的结点只剩一个(也就是根结点)。
public Node<T> createTree(List<Node<T>> nodes) {
while (nodes.size() > 1) {
Collections.sort(nodes);
Node<T> left = nodes.get(nodes.size() - 2);
left.setCode(0 + "");
Node<T> right = nodes.get(nodes.size() - 1);
right.setCode(1 + "");
Node<T> parent = new Node<T>(null, left.getWeight() + right.getWeight());
parent.setLeft(left);
parent.setRight(right);
nodes.remove(left);
nodes.remove(right);
nodes.add(parent);
}
return nodes.get(0);
}
- HuffmanTree类:得到相应字符的编码值
public List<Node<T>> breadth(Node<T> root) {
List<Node<T>> list = new ArrayList<Node<T>>();
Queue<Node<T>> queue = new ArrayDeque<Node<T>>();
if (root != null) {
queue.offer(root);
root.getLeft().setCode(root.getCode() + "0");
root.getRight().setCode(root.getCode() + "1");
}
while (!queue.isEmpty()) {
list.add(queue.peek());
Node<T> node = queue.poll();
if (node.getLeft() != null)
node.getLeft().setCode(node.getCode() + "0");
if (node.getRight() != null)
node.getRight().setCode(node.getCode() + "1");
if (node.getLeft() != null) {
queue.offer(node.getLeft());
}
if (node.getRight() != null) {
queue.offer(node.getRight());
}
}
return list;
}
- Word类:在其中我包含了空格和回车出现的可能。
char[] chars = new char[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's'
, 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ','\n'};
int[] number = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- Word类:因为加了空格和回车,所以小于28,得到每个字符出现的次数(类似于累加的形式)
//得到相应字符出现的次数
public void num(String string) {
for (int i = 0; i < 28; i++) {
int temp = 0;
for (int j = 0; j < string.length(); j++) {
if (string.charAt(j) == chars[i])
temp++;
}
number[i] += temp;
}
}
- HuffmanTreeTest:把读入的存进list中并进行排序整理,输出每个字母出现的次数,倒数第二个显示的为空格,最后一个显示的为回车
File file = new File("abc.txt");
Word read = new Word();
String temp = read.txtString(file);
System.out.println(temp);
int[] num = read.getNumber();
char[] chars = read.getChars();
for (int i = 0; i < 28; i++) {
System.out.print(chars[i] + ":" + num[i] + " ");
list.add(new Node<String>(chars[i] + "", num[i]));
}
Collections.sort(list);
System.out.println();
- 显示结果:
- HuffmanTreeTest:计算相应字母、空格与回车出现的概率
HuffmanTree huffmanTree = new HuffmanTree();
Node<String> root = huffmanTree.createTree(list);
list2 = huffmanTree.breadth(root);
for (int i = 0; i < list2.size(); i++) {
if (list2.get(i).getData() != null) {
list3.add(list2.get(i).getData());
list4.add(list2.get(i).getCode());
}
}
for (int i = 0; i < list2.size(); i++) {
num2 += list2.get(i).getWeight();
}
for (int i = 0; i < list3.size(); i++) {
System.out.println(list3.get(i) + "出现的概率为" + list2.get(i).getWeight() / num2 + " ");
}
System.out.println();
- 显示结果:
- HuffmanTreeTest:得到相应字母、空格与回车的对应编码值
for (int i = 0; i < list4.size(); i++) {
System.out.println(list3.get(i) + "的编码为" + list4.get(i) + " ");
}
System.out.println();
- 显示结果:
- HuffmanTreeTest:对原文件进行编码
for (int i = 0; i < temp.length(); i++) {
for (int j = 0; j < list3.size(); j++) {
if (temp.charAt(i) == list3.get(j).charAt(0))
result += list4.get(j);
}
}
System.out.println("编码后为:" + result);
for (int i = 0; i < result.length(); i++) {
list5.add(result.charAt(i) + "");
}
- 显示结果(太长了只截取了部分)
- HuffmanTree:进行解码
while (list5.size() > 0) {
temp2 = temp2 + "" + list5.get(0);
list5.remove(0);
for (int i = 0; i < list4.size(); i++) {
if (temp2.equals(list4.get(i))) {
temp3 = temp3 + "" + list3.get(i);
temp2 = "";
}
}
}
System.out.println();
- 显示结果
- HuffmanTree:把解码后的情况写入文件中
File file2 = new File("abc1.txt");
Writer out = new FileWriter(file2);
out.write(temp3);
out.close();
完整代码
读取与写入文本
20172332 2017-2018-2 《程序设计与数据结构》Java哈夫曼编码实验--哈夫曼树的建立,编码与解码的更多相关文章
- 2017-2018-2 1723《程序设计与数据结构》第十一周作业 & 实验三 & (总体)第三周结对编程 总结
作业地址 第十一次作业:https://edu.cnblogs.com/campus/besti/CS-IMIS-1723/homework/1933 (作业界面已评分,可随时查看,如果对自己的评分有 ...
- 2017-2018-2 1723《程序设计与数据结构》第三周作业 & 实验一 总结
作业地址 第三周作业:https://edu.cnblogs.com/campus/besti/CS-IMIS-1723/homework/1667 提交情况如图: 实验一:https://edu.c ...
- 2017-2018-2 1723《程序设计与数据结构》第八周作业 & 实验二 & 第一周结对编程 总结
作业地址 第八周作业:https://edu.cnblogs.com/campus/besti/CS-IMIS-1723/homework/1847 (作业界面已评分,可随时查看,如果对自己的评分有意 ...
- 2018面向对象程序设计(Java)第4周学习指导及要求
2018面向对象程序设计(Java) 第4周学习指导及要求(2017.9.19-2017.9. 26) 学习目标 掌握类与对象的基础概念,理解类与对象的关系: 掌握对象与对象变量的关系: 掌握预定 ...
- 20172301 2017-2018-2 《程序设计与数据结构》实验一《Java开发环境的熟悉》实验报告
20172301 2017-2018-2 <程序设计与数据结构>实验一<Java开发环境的熟悉>实验报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 郭 ...
- 20172319 2018.04.01-04.11 《Java程序设计》第5周学习总结
20172319 2018.04.01-04.11 <Java程序设计>第5周学习总结 目录 教材学习内容总结 教材学习中的问题和解决过程 代码调试中的问题和解决过程 代码托管 上周考试错 ...
- 《Java程序设计与数据结构教程(第二版)》学习指导
<Java程序设计与数据结构教程(第二版)>学习指导 欢迎关注"rocedu"微信公众号(手机上长按二维码) 做中教,做中学,实践中共同进步! 原文地址:http:// ...
- 20162323周楠《Java程序设计与数据结构》第六周总结
学号 2016-2017-2 <程序设计与数据结构>第六周学习总结 教材学习内容总结 继承:从已有类派生一个新类,是面向对象程序设计的一个特点 在Java中只支持单继承,不支持多继承 继承 ...
- 20162323周楠《Java程序设计与数据结构》第五周总结
20162323周楠 2016-2017-2 <程序设计与数据结构>第五周学习总结 教材学习内容总结 1.面向对象软件设计的基本部分是确定程序中应该创建哪些类: 2.面向对象程序设计的核心 ...
随机推荐
- Java笔试题解析(二)——2015届唯品会校招
曾经总是看别人写的笔经面经.今天自己最终能够写自己亲身经历的一篇了 T-T. 前阵子去了唯品会的秋招宣讲会,华工场(如今才知道原来找家互联网公司工作的人好多).副总裁介绍了VIP的商业模式是逛街式的购 ...
- #leetcode刷题之路49-字母异位词分组
给定一个字符串数组,将字母异位词组合在一起.字母异位词指字母相同,但排列不同的字符串.示例:输入: ["eat", "tea", "tan" ...
- Bootstrap02
Bootstrap02_内容概述 一.排版样式 (下面示例*代表class) 1.段落突出 *=lead <p>山外有山,<span class="lead"& ...
- Disruptor时序调用
接下来,我会对disruptor的设计和源码上进行讲解,先来一篇时序图,简单理解下disruptor的工作过程
- 使用uliweb创建一个简单的blog
1.创建数据库 uliweb的数据库都在models.py文件里面,因此先创建该文件 vim apps/blog/models.py 添加如下两行: #coding=utf-8 from uliweb ...
- 【转载】COM 组件设计与应用(十六)——连接点(vc.net)
原文:http://vckbase.com/index.php/wv/1257.html 一.前言 上回书介绍了回调接口,在此基础上,我们理解连接点就容易多了. 二.原理 图一.连接点组件原理图.左侧 ...
- Linux下多线程编程中信号量介绍及简单使用
在Linux中有两种方法用于处理线程同步:信号量和互斥量. 线程的信号量是一种特殊的变量,它可以被增加或减少,但对其的关键访问被保证是原子操作.如果一个程序中有多个线程试图改变一个信号量的值,系统将保 ...
- 【LNOI2014】LCA
题面 题解 考察\(dep[\mathrm{LCA}(i, x)]\)的性质,发现它是\(i\)和\(x\)的链交的长度. 那么对每个\(i\)所在的链打一个区间加标记,询问时算一下\(x\)所在的链 ...
- 2653: middle
2653: middle 链接 分析: 二分答案+主席树. 对于中位数的经典做法,就是二分一个数,将小于的变成-1,大于等于的变成+1,那么如果sum>=0(因为+1包括等于),L=mid+1, ...
- 2_C语言中的数据类型 (一)2.1.常量和字符串常量
2.1 常量就是在程序中不可变化的量,常量在定义的时候必须给一个初值. 1.1.1 #define 定义一个宏常量 1.1.2 const 定义一个const常量 ...





