13.5 赫夫曼编码

基本介绍:

  1. 赫夫曼编码也翻译为 哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,属于程序算法

  2. 赫夫曼编码是赫夫曼树在电讯通讯中的经典应用一致

  3. 赫夫曼编码广泛的应用与数据文件压缩,其 压缩率通常在20%~90%之间

  4. 赫夫曼是 可变字长编码(VLC)的一种。Huffman与1952年提出一种编码方式称之为 最佳编码

在线转码工具

赫夫曼编码压缩思路例:

  1. 获取一个字符串i like like like java do you like a java

  2. 然后统计各个字母出现的次数d:1 y:1 u:1 j:2 v:2 o:2 l:4 k:4 e:4 i:5 a:5 (空格):9

  3. 按照上面字符出现的次数当作叶子节点权值构建一颗霍夫曼树

  4. 根据赫夫曼树( 构建的赫夫曼树不一样,编码也可能不一样,因为可能存在两个相等的左右节点,所以赫夫曼树可能不一样,但是wpl是一样的,都是最小的),给各个字符规定编码,向左的路径为0,向右的路径为1,编码如下:

    o:1000 u:10010 d:100110 y:100111 i:101 a:110 k:1110 e:1111 j:0000 v:0001 l:001 (空格):01(不难看出不存在一个编码是另一个编码的前缀)

  5. 按照上面的赫夫曼编码,我们将i like like like java do you like a java字符串对应的编码(赫夫曼编码是无损压缩),通过赫夫曼长度变成 133,而使用 AscII码出来的长度是359

(1) Node{data(存放数据), weight(权值), left 和 right}

(2) 得到 i like like like java do you like a java对应的byte[] 数组

(3) 编写一个方法,将准备构建赫夫曼树的Node 节点放到 List , 形式[Node[data=97,weight=5], Node[data=32,weight=9]…],体现d:1 y:1 u:1 j:2 v:2 o:2 l:4 k:4 e:4 i:5 a:5 (空格):9

(4) 可以通过List创建对应的赫夫曼树

package huffmancode;import java.util.*;public class HuffmanCode {public static void main(String[] args) {String content = "i like like like java do you like a java";byte[] contentBytes = content.getBytes();System.out.println(contentBytes.length);byte[] huffmanCodeBytes = huffmanZip(contentBytes);System.out.println("压缩后的编码为"+Arrays.toString(huffmanCodeBytes));System.out.println("长度为:"+huffmanCodeBytes.length);// 分布过程
/*List<Node> nodes = getNode(contentBytes);System.out.println(nodes);Node huffmanTreeRoot = createHuffmanTree(nodes);System.out.println("前序遍历");huffmanTreeRoot.preOrder();// 测试是否生成了对应的赫夫曼编码Map<Byte, String> huffmanCodes = getCodes(huffmanTreeRoot);System.out.println("~生成的赫夫曼编码表:"+ huffmanCodes);// 测试huffmanCodeBytes = zip(contentBytes, huffmanCodes);System.out.println("huffmanCodeBytes="+Arrays.toString(huffmanCodeBytes));// 发送 HuffmanCodeBytes 数组
*/}// 使用一个方法,将前面的方法封装起来,便于我们的调用/**** @param bytes 原始的字符串对应的字节数组* @return 是经过 赫夫曼编码 处理后的字节数组(压缩后的数组)*/private static byte[] huffmanZip(byte[] bytes){List<Node> nodes = getNode(bytes);// 根据 nodes 创建赫夫曼树Node huffmanTreeRoot = createHuffmanTree(nodes);// 根据赫夫曼树创建赫夫曼编码Map<Byte, String> huffmanCodes = getCodes(huffmanTreeRoot);// 根据生成的赫夫曼编码,压缩得到压缩后的赫夫曼编码字节数组byte[] huffmanCodeBytes = zip(bytes,huffmanCodes);return huffmanCodeBytes;}// 编写一个方法,将一个字符串对应的byte[] 数组,通过生成的赫夫曼编码表,返回一个赫夫曼编码,压缩后的byte[]数组/**** @param bytes 这是原始的字符串对应的 byte[]* @param huffmanCodes  生成的赫夫曼编码 map* @return 返回赫夫曼编码处理后的 byte[]*/private static byte[] zip(byte[] bytes, Map<Byte,String> huffmanCodes){// 1. 利用 huffmanCodes 将 bytes 转成 赫夫曼编码对应的字符串StringBuilder stringBuilder = new StringBuilder();// 遍历 bytes 数组for (byte b: bytes){stringBuilder.append(huffmanCodes.get(b));}System.out.println(stringBuilder.toString());// 将 "101010001011111110..."转成 byte[]// 统计返回的 byte[] huffmanCodeBytes 长度int len;// 下面代码一句话搞定就是 len = (stringBuilder.length() + 7) / 8if (stringBuilder.length() % 8 == 0){len = stringBuilder.length() / 8;} else {len = stringBuilder.length() / 8 + 1;}// 创建一个存储压缩后的 byte数组byte[] huffmanCodeBytes = new byte[len];int index = 0; // 记录是第几个bytefor (int i = 0; i < stringBuilder.length(); i += 8){// 因为是每8为对应一个byteString strByte;if (i + 8 > stringBuilder.length()){// 不够8位了,那么有多少取多少strByte = stringBuilder.substring(i);} else {strByte = stringBuilder.substring(i, i + 8);}// 将strByte转成一个 byte 放入到 huffmanCodeByteshuffmanCodeBytes[index] = (byte)Integer.parseInt(strByte,2);index++;}return huffmanCodeBytes;}/**** @param bytes 接受字节数组* @return  返回是一个list形式*/private static List<Node> getNode(byte[] bytes){// 创建一个ArrayListArrayList<Node> nodes = new ArrayList<>();// 存储每个byte出现的次数  -> mapMap<Byte,Integer> counts = new HashMap<>();for (byte b: bytes){Integer count = counts.get(b);if (count == null){// 说明map还没有该字符数据counts.put(b,1);} else {counts.put(b, count+1);}}// 把每个键值对,转成一个node对象并加入弄得集合// 遍历mapfor (Map.Entry<Byte,Integer> entry:counts.entrySet()){nodes.add(new Node(entry.getKey(),entry.getValue()));}return nodes;}// 创建赫夫曼树private static Node createHuffmanTree(List<Node> nodes){while(nodes.size() > 1){// 排序(从小到大)Collections.sort(nodes);// 取出左右节点Node leftNode = nodes.get(0);Node rightNode = nodes.get(1);Node parent = new Node(null,leftNode.weight + rightNode.weight);parent.left = leftNode;parent.right = rightNode;// 删除左右节点nodes.remove(leftNode);nodes.remove(rightNode);// 将新的节点加入nodes.add(parent);}return nodes.get(0);}//前序遍历private static void preOrder(Node root){if (root != null){root.preOrder();}else{System.out.println("赫夫曼树为空");}}// 生成赫夫曼树对应的赫夫曼编码//思路:// 1. 将赫夫曼编码表存放在 Map<Byte,String>static Map<Byte,String> huffmanCodes = new HashMap<Byte, String>();// 2. 在生成赫夫曼编码表时,需要去拼接路径,定义一个 StringBuilder 存储某个叶子节点的路径static StringBuilder stringBuilder = new StringBuilder();// 为了方便,重载getCodesprivate static Map<Byte,String> getCodes(Node root){if (root == null){return null;}// 处理root左子树getCodes(root.left,"0",stringBuilder);// 处理root右子树getCodes(root.right, "1", stringBuilder);return huffmanCodes;}/*** 功能:将传入的node结点的所有叶子节点的赫夫曼编码得到,并放入到huffmanCodes* @param node  传入的节点(默认跟结点开始)* @param code  代表路径;左子节点代表0,右子节点表示1* @param stringBuilder 用于拼接路径的*/private static void getCodes(Node node, String code, StringBuilder stringBuilder){StringBuilder stringBuilder2 = new StringBuilder(stringBuilder);// 将code加入到 stringBuilder2stringBuilder2.append(code);if (node != null){ // 如果 node == null 不处理// 判断当前 node 是叶子节点还是非叶子节点if (node.data == null){// 非叶子节点,递归处理// 向左递归getCodes(node.left,"0",stringBuilder2);// 向右递归getCodes(node.right,"1",stringBuilder2);} else {// 说明是叶子节点// 就表示找到了某个叶子节点huffmanCodes.put(node.data,stringBuilder2.toString());}}}}
// 创建Node,存放数据和权值
class Node implements Comparable<Node>{Byte data; // 存放数据本身看,比如'a' = 97 ' (空格)'= 32int weight; // 权值,表示字符出现的次数Node left;Node right;public Node(Byte data, int weight) {this.data = data;this.weight = weight;}@Overridepublic int compareTo(Node o) {// 按照从小到大排序return this.weight - o.weight;}@Overridepublic String toString() {return "Node{" +"data=" + data +", weight=" + weight +'}';}//前序遍历public void preOrder(){System.out.println(this);if (this.left != null){this.left.preOrder();}if (this.right != null){this.right.preOrder();}}}

赫夫曼压缩(萌新劝退)相关推荐

  1. 赫夫曼压缩解压(java)

    霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树.所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数).树的路径长度 ...

  2. 赫夫曼树的经典应用——赫夫曼编码解码

    之前利用赫夫曼树来对字符串进行压缩,相当于对字符串加密.现在需要利用赫夫曼编码来进行解码,也就是解密. 如果还不了解赫夫曼编码的小伙伴可以先看上篇文章--利用哈夫曼树实现哈夫曼编码进行字符串压缩 之前 ...

  3. 用赫夫曼树进行文件的压缩

    思路分析 代码实现 package com.atguigu.huffmancode;import com.sun.org.glassfish.external.statistics.CountStat ...

  4. 数据结构之赫夫曼文件压缩解压

    一.文件压缩 具体要求:给你一个图片文件,要求对其进行无损压缩, 看看压缩效果如何. 思路:读取文件-> 得到赫夫曼编码表 -> 完成压缩 package com.ws.数据结构.树.赫夫 ...

  5. 武汉理工大学数据结构综合实验——二叉树与赫夫曼图片压缩

    文章目录 实验目的 主要仪器设备及耗材 一.实验要求 二.分析与设计 1.数据结构的设计 2.核心算法设计 生成Huffman树的算法 生成Huffman编码的算法 压缩编码的算法 3.测试用例设计 ...

  6. 【赫夫曼树详解】赫夫曼树简介及java代码实现-数据结构07

    赫夫曼树(最优二叉树) 1. 简介 定义: 赫夫曼树是n个带权叶子结点构成的所有二叉树中,带权路径长度(WPL)最小的二叉树. 叶子结点的带权路径: 叶子结点权值*到根节点的路径长度(叶结点的层数) ...

  7. 用赫夫曼树进行文件解压

    思路分析 代码实现 package com.atguigu.huffmancode;import com.sun.org.glassfish.external.statistics.CountStat ...

  8. 数据结构与算法——赫夫曼树基本实现

    目录 一.赫夫曼树 1.1 基本介绍 1.2 赫夫曼树创建步骤图解 1.3  代码实现 二.赫夫曼编码 2.1 基本介绍 2.1.1  通讯领域 - 定长编码 - 举例说明 2.1.2  通讯领域 - ...

  9. 赫夫曼树赫夫曼编码的创建

    目录 基础知识点 最优二叉树 如何构造赫夫曼树 赫夫曼编码 编码与压缩文件 代码 结构体设计 创建赫夫曼树 创建构建赫夫曼编码 基础知识点 赫夫曼树又称为最优树,是一种带权路径长短最短的树,有着广泛的 ...

最新文章

  1. 继往开来!目标检测二十年技术综述
  2. 论文简述 | DOT:面向视觉SLAM的动态目标跟踪
  3. Linux自动化测试monkey,APP自动化测试中Monkey和 MonkeyRunner
  4. 文巾解题3. 无重复字符的最长子串
  5. 五、Web服务器——MVC开发模式 EL表达式 JSTL 学习笔记
  6. Python中的+=
  7. 12个ggplot2扩展包帮你实现更强大的可视化
  8. Ubuntu 20.10安装docker
  9. ie对象不支持“jggrid“属性或方法_8.2 location 对象
  10. 共享hp无线扫描到计算机,共享HP / HP扫描仪的OpenWrt路由器
  11. echart曲线图的使用
  12. mediawiki java api_MediaWiki API 帮助
  13. CSDN使用Markdown编辑器
  14. 分而治之 (25 分)
  15. {“error“:“incorrect region, please use up-z1.qiniup.com“}
  16. 快速排序算法原理 Quicksort —— 图解(精讲) JAVA
  17. matlab中eacf函数,基于MATLAB的切比雪夫I型模拟低通滤波器设计
  18. linux职位,linux现在最火的职位是什么
  19. 【BZOJ】【双倍的幸福】【双(三)倍的经验】
  20. 2019年1月份GitHub上最热门的开源项目

热门文章

  1. 短视频无尽流前端开发指南
  2. 【RMQ】POJ 3264 Balanced Lineup
  3. 阿里任务调度SchedulerX2.0和阿里云大数据任务结合
  4. 求助:“[‘Pacch‘] not in index“(Kaggle泰坦尼克号模型)
  5. tf神经网络模型预测泰坦尼克号生还
  6. mysqld: File './mysql-bin.index' not found (Errcode: 13 - Permission denied)
  7. 异步六进制加法计数器
  8. javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? HTTPS请求异常
  9. 设置里怎么开启微信定位服务器,微信定位开启怎么设置(如何开启微信定位功能)...
  10. KMP算法-严蔚敏数据结构