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

赫夫曼树节点

/*** 创建Node,包含数据和权值*/
public class Node implements Comparable<Node> {//存放字符串本身Byte data;//存放权值 字符出现的次数int weight;Node left;Node right;public Node(int weight) {this.weight = weight;}public Node(Byte data, int weight) {this.data = data;this.weight = weight;}/*** 前序遍历*/public void preOrder() {System.out.println(this);if (this.left != null) {this.left.preOrder();}if (this.right != null) {this.right.preOrder();}}@Overridepublic int compareTo(Node o) {return this.weight - o.weight;}@Overridepublic String toString() {return "Node{" +"date=" + data +", weight=" + weight +'}';}
}

压缩、解压、测试代码

import java.io.*;
import java.util.*;public class HuffmanCode {//    赫夫曼编码 32=01, 97=100, 100=11000, 117=11001, 101=1110, 118=11011, 105=101, 121=11010, 106=0010, 107=1111, 108=000, 111=0011static Map<Byte, String> huffmanCodes = new HashMap<>();public static void main(String[] args) {String content = "i like like like java do you like a java";byte[] strByte = content.getBytes();System.out.println("压缩前数组" + Arrays.toString(strByte));System.out.println("压缩前数组长度" + strByte.length);//压缩byte[] huffmanCodeBytes = huffmanZip(strByte);System.out.println("压缩后数组" + Arrays.toString(huffmanCodeBytes));System.out.println("压缩后数组长度" + huffmanCodeBytes.length);//解压byte[] sourceByte = decode(huffmanCodes, huffmanCodeBytes);System.out.println("解压后数组" + Arrays.toString(sourceByte));System.out.println("解压后数组长度" + sourceByte.length);//解压后数据System.out.println(new String(sourceByte));//String srcFile = "D:\\demo.png";//String zipFile = "D:\\demo.zip";//zipFile(srcFile, zipFile);//System.out.println("压缩文件成功");String zipFile = "D:\\demo.zip";String dstFile = "D:\\demo2.png";unZipFile(zipFile,dstFile);}/*** 赫夫曼解压** @param zipFile 准备解压的文件* @param dstFile 解压后的文件存放目录*/public static void unZipFile(String zipFile, String dstFile) {//定义文件输入流InputStream is = null;//定义一个对象输入流ObjectInputStream ois = null;//定义文件输出流OutputStream os = null;try {//创建文件输入流is = new FileInputStream(zipFile);//创建一个和is关联的对象输入流ois = new ObjectInputStream(is);//读取byte数组,huffmanBytesbyte[] huffmanBytes = (byte[]) ois.readObject();//读取赫夫曼编码表Map<Byte, String> huffmanCode = (Map<Byte, String>) ois.readObject();//    解码byte[] bytes = decode(huffmanCode, huffmanBytes);//    将解码后字节流写入目标文件os = new FileOutputStream(dstFile);os.write(bytes);} catch (Exception e) {throw new RuntimeException(e);} finally {try {os.close();ois.close();is.close();} catch (IOException e) {throw new RuntimeException(e);}}}/*** 编写方法,将文件进行压缩** @param srcFile 压缩文件全路径* @param dstFile 压缩后文件输出路径*/public static void zipFile(String srcFile, String dstFile) {//创建输入流FileInputStream inputStream = null;//创建输出流FileOutputStream outputStream = null;ObjectOutputStream oos = null;try {//创建文件输出流inputStream = new FileInputStream(srcFile);//     创建一个和源文件大小一样的byte[]int inputSize = inputStream.available();byte[] bytes = new byte[inputSize];//读取文件inputStream.read(bytes);//压缩文件byte[] zipBytes = huffmanZip(bytes);//创建文件输出流,存放压缩文件outputStream = new FileOutputStream(dstFile);//创建一个和文件输出流相关的ObjectOutputStreamoos = new ObjectOutputStream(outputStream);//   将赫夫曼编码后的字节数组写入压缩文件oos.writeObject(zipBytes);// 以对象流写入赫夫曼编码,oos.writeObject(huffmanCodes);} catch (IOException e) {throw new RuntimeException(e);} finally {try {inputStream.close();outputStream.close();oos.close();} catch (IOException e) {System.out.println(e.getMessage());}}}/*** 对压缩数据的解码** @param huffmanCodes* @param huffmanByte* @return*/private static byte[] decode(Map<Byte, String> huffmanCodes, byte[] huffmanByte) {//将赫夫曼编码数组转换为二进制字符串StringBuffer stringBuffer = new StringBuffer();for (int i = 0; i < huffmanByte.length; i++) {//最后一位不需要补高位if (i != huffmanByte.length - 1) {stringBuffer.append(byteToBitString(true, huffmanByte[i]));} else {stringBuffer.append(byteToBitString(false, huffmanByte[i]));}}//根据赫夫曼编码表,反写解码表Map<String, Byte> decodeMap = new HashMap<>();for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {decodeMap.put(entry.getValue(), entry.getKey());}//创建要给的集合,存放byteList<Byte> list = new ArrayList<>();StringBuffer key = new StringBuffer();for (int i = 0; i < stringBuffer.length(); i++) {key.append(stringBuffer.substring(i, i + 1));Byte aByte = decodeMap.get(key.toString());if (aByte != null) {list.add(aByte);key = new StringBuffer();}}//构造返回数据byte[] res = new byte[list.size()];for (int i = 0; i < list.size(); i++) {res[i] = list.get(i);}return res;}/*** 将一个byte转成一个二进制的字符串** @param b    传入的byte* @param flag 标志是否需要补高位,如果为true,表示需要补高位* @return byte对应的二进制字符串(按照补码返回)*/private static String byteToBitString(boolean flag, byte b) {//  使用变量保存b 将b转换为intint temp = b;//如果是正数,需要补高位 1 0000 0000 | 0000 0001= 10000 0001if (flag) {temp |= 256;}//返回对应二进制的补码String str = Integer.toBinaryString(temp);if (flag) {return str.substring(str.length() - 8);} else {return str;}}/*** 将字节数组压缩为赫夫曼数组** @param bytes* @return*/private static byte[] huffmanZip(byte[] bytes) {//获取赫夫曼树节点List<Node> nodes = getNodes(bytes);//创建霍夫曼树Node huffmanTree = createHuffmanTree(nodes);//生成霍夫曼编码getCodes(huffmanTree);//压缩数据return zip(bytes, huffmanCodes);}/*** 将字符串对应的byte[]数组,通过生成的赫夫曼编码表,返回一个赫夫曼编码压缩后的byte[]** @param bytes        这是原始的字符串对应的byte[]* @param huffmanCodes 生成的赫夫曼编码map* @return 返回赫夫曼处理后的byte* 10101000补码  反码10101000-1=10100111 原码11011000 -(24+64)*/private static byte[] zip(byte[] bytes, Map<Byte, String> huffmanCodes) {StringBuffer temp = new StringBuffer();for (byte b : bytes) {temp.append(huffmanCodes.get(b));}//计算新数组长度 int len=(tem.length()+7)/8int len;if (temp.length() % 8 == 0) {len = temp.length() / 8;} else {len = temp.length() / 8 + 1;}//创建存储压缩后的byte数组;byte[] huffmanCodeBytes = new byte[len];//记录第几个byteint index = 0;for (int i = 0; i < temp.length(); i += 8) {String strByte;if (i + 8 > temp.length()) {strByte = temp.substring(i);} else {strByte = temp.substring(i, i + 8);}//将字符串二进制转换为bytehuffmanCodeBytes[index] = (byte) Integer.parseInt(strByte, 2);index++;}return huffmanCodeBytes;}/*** 重载** @param root*/private static void getCodes(Node root) {if (root != null) {getCodes(root.left, "0", new StringBuffer());getCodes(root.right, "1", new StringBuffer());}}/*** 将传入的node节点的所有叶子节点的赫夫曼编码得到,放到huffmanCodes集合** @param node         传入节点* @param code         路径:左子节点0,右子节点1* @param stringBuffer 用于路径拼接*/private static void getCodes(Node node, String code, StringBuffer stringBuffer) {StringBuffer temp = new StringBuffer(stringBuffer);temp.append(code);if (code != null) {//飞叶子结点if (node.data == null) {//左递归getCodes(node.left, "0", temp);//右递归getCodes(node.right, "1", temp);} else {//处理叶子节点huffmanCodes.put(node.data, temp.toString());}}}/*** 前序打印** @param root*/private static void preOrder(Node root) {if (root != null) {root.preOrder();} else {System.out.println("赫夫曼树为空");}}/*** 接受数组返回节点集合** @param bytes* @return*/private static List<Node> getNodes(byte[] bytes) {//    创建一个ArrayListArrayList<Node> nodes = new ArrayList<>();//创建一个map保存byte出现的次数HashMap<Byte, Integer> counts = new HashMap<>();for (byte b : bytes) {Integer num = counts.get(b);if (num == null) {counts.put(b, 1);} else {counts.put(b, ++num);}}//构建集合for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {nodes.add(new Node(entry.getKey(), entry.getValue()));}return nodes;}/*** 创建赫夫曼树** @param nodes* @return*/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);}
}

压缩前数据长度为40,压缩后数据长度为17.

压缩前数组[105, 32, 108, 105, 107, 101, 32, 108, 105, 107, 101, 32, 108, 105, 107, 101, 32, 106, 97, 118, 97, 32, 100, 111, 32, 121, 111, 117, 32, 108, 105, 107, 101, 32, 97, 32, 106, 97, 118, 97]
压缩前数组长度40
压缩后数组[-88, -65, -56, -65, -56, -65, -55, 77, -57, 6, -24, -14, -117, -4, -60, -90, 28]
压缩后数组长度17
解压后数组[105, 32, 108, 105, 107, 101, 32, 108, 105, 107, 101, 32, 108, 105, 107, 101, 32, 106, 97, 118, 97, 32, 100, 111, 32, 121, 111, 117, 32, 108, 105, 107, 101, 32, 97, 32, 106, 97, 118, 97]
解压后数组长度40
i like like like java do you like a java

赫夫曼压缩解压(java)相关推荐

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

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

  2. 赫夫曼压缩(萌新劝退)

    13.5 赫夫曼编码 基本介绍: 赫夫曼编码也翻译为 哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,属于程序算法 赫夫曼编码是赫夫曼树在电讯通讯中的经典应用一致 赫夫曼编 ...

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

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

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

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

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

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

  6. C语言哈夫曼编码压缩解压

    C语言哈夫曼编码压缩解压 一.实验目的 掌握哈夫曼编码基本运算以及存储结构表示. 二.实验内容: 1.系统要求包含以下功能 1)初始化:从终端读入字符集大小n,以及n个字符和n个权值(或者读入字符集和 ...

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

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

  8. Java版赫夫曼编码字节和赫夫曼解码

    文章收藏的好句子:变好的过程都不太舒服,试试再努力点. 目录 1.赫夫曼编码字节 1.1 赫夫曼编码字节数组 1.2 赫夫曼编码压缩后的字节数组转换成二进制编码 1.3 赫夫曼解码 1.赫夫曼编码字节 ...

  9. java振动数据压缩_【数据结构-Java】最佳实践-数据压缩(使用赫夫曼树)

    一.需求 将给出的一段文本,比如 "i like like like java do you like a java" , 根据前面的讲的赫夫曼编码原理,对其进行数据压缩处理 二. ...

最新文章

  1. 云服务器可以安装操作系统么,云服务器能装操作系统吗
  2. Linux下搭建高效的SVN
  3. Axure 6.5 RP下载,汉化
  4. SQLServer2000数据库特有的1433端口号
  5. 加快mysql导入、导出速度
  6. 中国速度之二神山建设(2):完善的项目计划,高效能价值流 | IDCF DevOps案例研究...
  7. linux基础知识——IPC之管道
  8. android 按钮顶级效果_Android 源码之button高亮效果
  9. 红橙Darren视频笔记 Activity启动流程(API28)
  10. python导入自己写的包_python的模块,包和目录的区别和自定义包的注意点
  11. Happy Week
  12. 实现JPA的懒加载和无外键
  13. 在构建好XPE操作系统上增加EWF功能
  14. 归并排序算法(java实现)
  15. Matlab中插值函数汇总和使用说明
  16. Cisco(思科)无线路由器
  17. Java实现DOC文件转DOCX文件
  18. 管家婆物流配货单快速实现批量拣货
  19. C# web references 调用出错 The underlying connection was closed: An unexpected error occurred on a send.
  20. 修改HTK代码,让其支持中文

热门文章

  1. MATLAB系列笔记:修改编辑器颜色为护眼色(绿豆沙)
  2. windows下断网启动程序
  3. 点餐系统架构模型_餐馆点餐系统课程设计
  4. ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to
  5. python用循环打出阶梯图形_Python制图你真的会吗?一文学会如何绘制漂亮的阶梯图...
  6. 二叉树的前序遍历(Java)
  7. babel7 + corejs3升级
  8. 【散文】 醉月湖畔,为谁染红妆
  9. 前端自动化测试之chai.js断言库
  10. 【人工智能 AI 2.0】阿里VP贾扬清被曝将离职创业:建大模型基础设施 已火速锁定首轮融资