还记得第一次接触哈夫曼树是在大二的数据结构课上,大家也都知道哈树的生成规则,很简单也很容易理解。给你N个带权的节点,让你生成一颗哈树,相信大部分人都没有问题。而正是这种表面看似很简单的东西,我们就容易无视。我坦白,那年数据结构的学习,对于哈树这一块,我没有敲过一行代码,更没有去想过他存在的意义以及利用哈树能解决什么样的问题。
大三进入蓝杰,重新接触到了哈夫曼树。这个沉寂在我脑海已久且濒临消亡的知识点,仿佛又渐渐地回来了。也让我开始思考哈夫曼树存在的意义。在IT这么一个日新月异的领域,一个技术之所以能够存在,一定是有其价值的,他一定是能给我们决绝问题带来利益的。通过查找给方面的资料,发现哈弗曼的用处确实很广,尤其是在数据通信、图像处理、数据压缩等方面有着很大的用处。
下面,我想通过手动建造一棵哈夫曼树,再次走进哈夫曼的世界。 ------
一、哈弗曼的基础知识
大家要了解一下哈夫曼树的基础知识。网上有很多解释,度娘说的比我清楚,这里就不占用篇幅多做解释。
下图是建造一颗哈树的过程....
二、 进入主题--------代码的实现
(1)首先,定义一个树的节点类
/** * 哈夫曼树节点的定义 * * @author Administrator * */ public class HuffmanNode { // 成员属性 private HuffmanNode left_child = null; private HuffmanNode right_child = null; private HuffmanNode parend = null; // 权值 private int obj; public HuffmanNode getLeft_child() { return left_child; } public void setLeft_child(HuffmanNode left_child) { this.left_child = left_child; } public HuffmanNode getRight_child() { return right_child; } public void setRight_child(HuffmanNode right_child) { this.right_child = right_child; } public HuffmanNode getParend() { return parend; } public void setParend(HuffmanNode parend) { this.parend = parend; } public int getObj() { return obj; } public void setObj(int obj) { this.obj = obj; } // 构造函数 public HuffmanNode(int obj) { this.obj = obj; } }
(2)生成一颗哈树
这里用到了一个新的知识点---优先队列。因为哈夫曼树的构造规则是每次要取根节点权值最小的两棵树出来。所以我们必须根据这些根节点权值大小,将这些树进行排序。 优先队列恰好为我们提供了这项功能,我们通过重新定义Comparator比较器,可以设定自己想要的排序规则,十分方便。
Comparator<HuffmanNode> comparator = new Comparator<HuffmanNode>() { @Override public int compare(HuffmanNode o1, HuffmanNode o2) { int numbera = o1.getObj(); int numberb = o2.getObj(); if (numberb < numbera) { return 1; } else if (numberb > numbera) { return -1; } else { return 0; } } };
核心语句----哈树的生成
从森林中每次取根节点权值最小的两棵树出来,形成一棵新树,其权值为两树根绝点权值之和。并将这两棵树分别作为新树的左右子树。循环往复,知道深林中只剩下1棵树。那么,这棵树就是我们要找的哈夫曼树。
/** * 生成哈夫曼树的方法 * @param queue 优先队列 */ private void creathuffman(PriorityQueue<HuffmanNode> queue) { while (queue.size() != 1) { // 取得两个最小的节点 HuffmanNode node1 = queue.poll(); HuffmanNode node2 = queue.poll(); // 生成一个新的节点 HuffmanNode node3 = new HuffmanNode(node1.getObj() + node2.getObj()); node3.setLeft_child(node1); node3.setRight_child(node2); queue.add(node3); } }
(3)打印所生成的哈树(通过先序遍历)
// 打印哈夫曼树的方法 private void printhuffman(HuffmanNode rootnode) { // 指定根节点,从根节点开始找 HuffmanNode temp = rootnode; // 打印根节点的值 System.out.print("【"+temp.getObj()+"】" + " "); if (rootnode.getLeft_child() != null) { temp = rootnode.getLeft_child(); // 递归调用自己,表示只要左节点不为空,就把左节点作为新的根节点继续上边步奏 printhuffman(temp); } if (rootnode.getRight_child() != null) { temp = rootnode.getRight_child(); printhuffman(temp);// 同上 } }
至此,我们的哈夫曼树的生成过程已经演示完毕。刚才也说了,哈夫曼树的用处还有很多,我们能够创建他,也只是完成其中最基础的要求,我们不能止步于此。当然,我们不能认为这些东西很简单,就去轻视他,自己没有动手做过,你是不会知道什么叫做说着简单做着难的。
好啦, 之后我们会通过一个文件压缩程序的演示,其中包括了哈弗曼编码的生成,对象的序列化,文件的读出与写入等问题,跟大家进一步分享哈弗曼在数据编码上的用途。
相关推荐
- 实验目的:介绍为什么要学习和使用哈弗曼树,以及在数据压缩中的作用。 - 实验原理:详细解释哈弗曼树的构造方法和编码解码过程。 - 实现细节:列出C语言实现的关键代码片段,如节点结构体定义、优先队列的实现...
- 接着,使用优先队列(通常用最小堆实现)来存储这些节点,每次取出频率最小的两个节点合并成一个新的节点,新节点的频率是两个子节点频率之和,将新节点再次插入队列。 - 这个过程重复,直到队列中只剩下一个...
【哈弗曼编码】是一种高效的无损数据压缩方法,它基于概率分布构建最优的前缀编码。...通过这样的实验,学生不仅可以学习到Matlab的编程技巧,还能深入理解哈弗曼编码的理论和应用,同时提升独立解决问题的能力。
哈弗曼编码是一种高效的数据压缩方法,...在学习哈弗曼编码时,了解其基本原理、构建过程以及如何实现编码和解码是非常重要的。通过实践编写或理解相关的程序,能够加深对这一数据压缩技术的理解,提升解决问题的能力。
通过这个课程设计,学生能够体验到理论知识转化为实际应用的过程,对今后的学习和工作有着重要的指导意义。 总之,哈弗曼编码是数据压缩的重要方法,通过构建哈弗曼树来优化编码,有效提高了数据传输和存储的效率。...
新节点作为父节点,两个子节点作为其叶子节点,再次插入优先队列。重复此过程直到队列只剩下一个节点,即得到哈夫曼树。 3. **生成哈夫曼编码**:从哈夫曼树的根节点开始,左子节点表示0,右子节点表示1,自底向上...
霍夫曼编码是一种高效的数据压缩方法,主要用于无损数据压缩。...通过学习和实践霍夫曼编码,可以加深对数据结构、算法以及位操作的理解,这些技能在处理大数据、网络传输和文件存储等领域都有着广泛的应用。