那么,什么是霍夫曼树(赫夫曼树)呢?

给定n个权值(权值就是每个节点里面存放的数据,但是根据业务需求不同,存放的数据类型有些差别)作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

看这个定义你肯定也很懵,我这里举一个例子,就不要专研这个定义了,通过图形可以很快的看懂

例如:权值分别为 5,3,9,1,6的这几个节点构建一颗二叉树

首先排序这样创建的二叉树才是有序的

那么排序的结果就是 1,3,5,6,9,然后把每个节点当做一颗最简单的二叉树,排序结果如下:

那么第二次操作:把前面两个权值加起来构建一个新的节点,然后把这个节点和前两个节点合并成一个二叉树,然后继续排序:

继续下去:

最后一步:

这就是一颗霍夫曼树了,注意观察,所有的有效数据都是叶子节点。

那么如何创建赫夫曼树和赫夫曼编码呢?

在这里,我们假如有一段话,然后我们需要统计这句话里面的所有的字符和对应出现的次数,我们就可以把次数当做权值,把每一个字符和字符出现的次数包装起来作为一个节点!

根据上面的思路,我们首先创建一个节点类型,用于存放字符和它出现的次数

​
class Node1 implements Comparable{  //这个是节点类public Byte ch;  //存放字符public int count; //存放字符出现的次数public Node1 leftNode1; //左指针public Node1 rightNode1; //右指针public Byte getCh() {return ch;}public void setCh(Byte ch) {this.ch = ch;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}@Overridepublic String toString() {return "Node1{" +"ch=" + ch +", count=" + count +'}';}@Overridepublic int compareTo(Object o) {Node1 node1 = (Node1)o;return this.count - node1.count;}public Node1(Byte ch,int count) {this.ch = ch;this.count = count;}public void pre() {   //前序遍历System.out.println(this);if (this.leftNode1 != null) {this.leftNode1.pre();}if (this.rightNode1 != null) {this.rightNode1.pre();}}
}​

我们通过建立集合来进行统计每个字符出现的次数

​
public static List<Node1> putNode(byte[] bytes) { //这里传入byte数组的原因是因为字符串当中有把字符串转成byte[]数组进行存储的方法,所以我这里用byte[]接收它,当然写法不唯一,可以直接传字符串,然后把map的第一个泛型改成字符型,然后遍历字符串也是可以的ArrayList<Node1> arrayList = new ArrayList<Node1>();Map<Byte,Integer> m = new HashMap<Byte,Integer>();for (byte b : bytes) {Integer integer = m.get(b);  //这里使用map的原因就是因为k值不可以重复,这样的话我就可以把每一个字符当中k值,出现的次数当中v值,这样就简化了大量代码if (integer == null) {m.put(b,1);}else {m.put(b,m.get(b)+1);}}for (Map.Entry<Byte,Integer> entry : m.entrySet()) {arrayList.add(new Node1(entry.getKey(),entry.getValue()));//最后遍历map集合,把它的所有元素new成Node1型,放入ArrayList当中}return arrayList;}​

下面的就是赫夫曼树的创建过程了,你可以从下面的代码中看出,把节点放在集合当中十分便于操作

public static Node1 createHuffmanTree(List<Node1> list) {while (list.size()>1) {Collections.sort(list);Node1 leftNode1 = list.get(0);Node1 rightNode1 = list.get(1);Node1 father = new Node1(null,leftNode1.count+ rightNode1.count);father.leftNode1 = leftNode1;father.rightNode1 = rightNode1;list.remove(1);list.remove(0);list.add(father);}return list.get(0);}

在上面的代码最后就返回了赫夫曼树的根节点,最后我们需要构建霍夫曼编码,构建方式其实也很简单,我们规定向左走为0,向右走为1,那么最后每一个字符对应的编码肯定不相同

例如节点1的霍夫曼编码:000,节点3的编码为:001,以此类推。

static StringBuilder stringBuilder = new StringBuilder();static Map<Byte,String> map = new HashMap<Byte,String>();public static void getNode(Node1 node1,String code,StringBuilder stringBuilder) {//第一个参数:二叉树的根节点,因为就是遍历二叉树来实现构建霍夫曼编码的
//第二个参数:编码,如果往左走就传0,往右走就传1,主方法当中传空字符串
//第三个参数:stringBuilder,上一个节点的霍夫曼编码StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);stringBuilder1.append(code);
//这里继续newStringBuilder并且append(code)的原因是为了记录下当前这个节点的霍夫曼编码
//放在递归时丢失if (node1.ch != null) { //这里的判断依据是创建霍夫曼代码时,我把非有效的节点Byte传了nullmap.put(node1.ch,stringBuilder1.toString());}else {  //回溯思想getNode(node1.leftNode1,"0",stringBuilder1); //先向左递归,后向右递归getNode(node1.rightNode1,"1",stringBuilder1);}}

最后一步:压缩霍夫曼树

压缩方式:把我们传的一段字符串转成由霍夫曼编码方式组成,然后以8个一位压缩霍夫曼编码

public static byte[] zip(byte[] bytes,Map<Byte,String> map1) {//这里的bytes也是字符串转成byte数组StringBuilder stringBuilder = new StringBuilder();for (byte b : bytes) {stringBuilder.append(map.get(b));  //在上面的代码中,我们用成员变量map存放了每个字符对应的霍夫曼编码,这里我们就可以通过对应的字符找到对应的霍夫曼编码}int length = 0;if (stringBuilder.length() % 8 == 0) {length = stringBuilder.length() / 8;}else {length = stringBuilder.length() / 8 + 1;}int index = 0;byte[] bytes1 = new byte[length];for (int i = 0; i < stringBuilder.length(); i += 8) {if (i+8 < stringBuilder.length()) {bytes1[index++] = (byte)Integer.parseInt(stringBuilder.substring(i,i+8));}else {bytes1[index++] = (byte)Integer.parseInt(stringBuilder.substring(i));}}return bytes1;}

创建霍夫曼树,霍夫曼编码以及使用霍夫曼编码压缩文件相关推荐

  1. 算法学习笔记——数据结构:哈夫曼树、带权路径长度WPL、哈夫曼编码

    引入 合并果子问题如下: 有n堆果子,每次可以合并任意两堆果子,耗费体力值为[两堆果子数之和],最终在n-1次合并后,得到一堆果子. 给出合并的方案,使得耗费的体力值最小 例如有3堆果子,质量依次为1 ...

  2. 哈夫曼树(最优二叉树)、哈夫曼编码

    在此祝大家新年快乐,新的一年守住头发,不断进步! 哈夫曼树 一.哈夫曼树基本概念 二.哈夫曼树的构造算法 三.哈夫曼构造算法的实现 四.哈夫曼编码 五.哈夫曼编码的算法实现 一.哈夫曼树基本概念 (1 ...

  3. 哈夫曼树带权路径长度c语言,【哈夫曼树】求结点的哈夫曼的带权路径长度

    本文用C++采用顺序存储实现求哈夫曼树(即最小生成树)的带权路径长度 努力 下面来了解一下哈夫曼树的构造以及如何求带权路径长度: 哈夫曼树为带权路径长度最小的树 哈夫曼树 哈夫曼树的顺序存储 [问题描 ...

  4. c语言哈夫曼树统计字母频率,C语言实现哈夫曼树

    本文实例为大家分享了C语言实现哈夫曼树的具体代码,供大家参考,具体内容如下 //哈夫曼树C语言实现 #include #include typedef struct HuffmanNode { cha ...

  5. Python实现霍夫曼树

    Python实现霍夫曼树 霍夫曼树是一种特殊的二叉树,是一种带权路径长度最短的二叉树,又称为最优二叉树. 给定 N 个权值作为二叉树的 N 个叶节点的权值,构造一棵二叉树,若该二叉树的带权路径长度达到 ...

  6. 霍夫曼树及霍夫曼编码的C语言实现,霍夫曼树及霍夫曼编码的C语言实现

    从周五开始学习霍夫曼树,一直到今天终于完成,期间遇到了各类各样的棘手的问题,经过一遍遍在纸上分析每一步的具体状态得以解决.如今对学习霍夫曼树的过程加以记录web 首先介绍霍夫曼树数组 霍夫曼树(Huf ...

  7. 霍夫曼树和霍夫曼编码以及霍夫曼编码的应用

    文章目录 霍夫曼树介绍 1.1霍夫曼树的定义 1.2霍夫曼树的几个概念 1.3构建霍夫曼树的过程 1.4代码实现霍夫曼树 霍夫曼编码介绍 什么是霍夫曼编码 通信领域的应用 字符串压缩 1.构造霍夫曼树 ...

  8. 霍夫曼树、霍夫曼编码

    霍夫曼树 一.基本介绍 二.霍夫曼树几个重要概念和举例说明  构成霍夫曼树的步骤: 举例:以arr = {1  3  6  7  8   13   29} public class HuffmanTr ...

  9. 深入学习二叉树(三) 霍夫曼树

    深入学习二叉树(三) 霍夫曼树 1 前言 霍夫曼树是二叉树的一种特殊形式,又称为最优二叉树,其主要作用在于数据压缩和编码长度的优化. 2 重要概念 2.1 路径和路径长度 在一棵树中,从一个结点往下可 ...

  10. 数据结构(六)霍夫曼树与编码

    1.算法流程 (1)构建霍夫曼树:自底向上 根据统计频率构建霍夫曼树: A.把所有的节点扔进排序队列queue中: B.从queue选择选择前面两个最小的元素a.b,把最小的树a作为左节点,把最小的b ...

最新文章

  1. mysql布隆过滤器源码_通过实例解析布隆过滤器工作原理及实例
  2. Android分包方案multidex
  3. MYSQL创建一个function用来计算经纬度距离
  4. Jenkins 程序目录
  5. pandas用众数填充缺失值_7步搞定数据清洗-Python数据清洗指南
  6. [图形学]拉普拉斯网格变形(Laplace Deformation)原理及复现
  7. 报童问题求解最大利润_Ortools调用第三方求解器
  8. win10远程关机命令
  9. 怎么让模糊的数字变清楚_如何用ps将模糊图片变清晰?
  10. 斐讯路由怎么设置虚拟服务器,192.168.2.1斐讯路由器设置的方法?
  11. linux下raid0创建教程,Linux RAID0阵列搭建
  12. 完全依赖XP必将自食其果
  13. linux基础(五)----linux命令系统学习----系统管理命令
  14. Facebook一季报解读:未来十年要打造一个怎样的世界?
  15. SW3516中文资料书
  16. ElementUi轮播图走马灯添加图片
  17. lisp实战文库_AutoLISP基础入门案例,很受用-推荐下载
  18. Hacknet 游戏笔记记录
  19. 经济型EtherCAT运动控制器(八):轴参数与运动指令
  20. codeforces1421 E Swedish Heroes

热门文章

  1. SQL注入——HTTP头部注入
  2. 一张图搞懂Ajax原理
  3. Laravel 模型hasOne、hasMany、belongsTo详细举例说明
  4. 题目 1042: 电报加密
  5. ReportViewer 工具栏为英文
  6. 2022 年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题——纯享题目版
  7. jieba分词、词性标注、停用词
  8. Java设计模式之创建型-建造者模式 (Builder)
  9. LED屏幕初始化以及设置屏参
  10. 炉石传说android版多大内存,炉石传说手机版对手机配置要求高吗? 炉石传说手机版最低配置详细介绍[图]...