目标:将字符串“can you can a can as a can canner can a can.”编码再解码

流程:

  1. 将字符串转成bytes (byte[]格式)(eg.[99,97,110....])
  2. 霍夫曼编码
    1. 统计bytes中各字节出现的次数,存于Map中(形如:{“字节”:c,“次数”:11}....),继而创建出对应的List<Node>
    2. 构建霍夫曼树
      • 将List<node>中按node的value排序
      • 合并最小的二个node(一开始是node,后面是树),构成一个新树
      • 将新树加入List<node>中,并移除最小的node(一开始是node,后面是树)
      • 循环至List<node>中只剩一颗树
    3. 利用霍夫曼树构建霍夫曼编码表(个人感觉是难点)
    4. 利用霍夫曼编码表编码bytes获得霍夫曼码(只有0、1)
    5. 将霍夫曼码转成字节数组(byte[]格式,8个一组,剩余直接转)
  3. 霍夫曼解码
    1. 将字节数组转成霍夫曼码(只有0、1)
    2. 对照霍夫曼编码表去解码霍夫曼码
  4. 将byte[]格式转字符串输出

    代码实现:

霍夫曼编解码代码

package demo10;import java.nio.file.attribute.AclEntry.Builder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64.Decoder;
import java.util.List;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;public class WangTestHuffmanCode {public static void main(String[] args) {String msg = "can you can a can as a can canner can a can.";//将字符串转字节byte[] bytes = msg.getBytes();//霍夫曼编码byte[] b = huffmanZip(bytes);//霍夫曼解码byte[] newBytes = decoder(huffList, b);//将字节转字符串System.out.println(new String(newBytes));}/*** 霍夫曼解码* @param huffList2* @param b* @return*/private static byte[] decoder(Map<Byte, String> huffList, byte[] b) {//将b转成二进制字符串(非最后以为转成8位字符串,最后一位正常转)StringBuffer sb = new StringBuffer();for(int i=0; i<b.length; i++) {if(i<b.length-1) {             String binStr = Integer.toBinaryString((b[i] & 0xFF) + 0x100).substring(1);sb.append(binStr);}else {String binStr = Integer.toBinaryString(b[i] & 0xFF);sb.append(binStr);}}System.out.println(sb);//对照huffList,转化成byte数组//重定义霍夫曼编码表HashMap<String, Byte> newhuffList = new HashMap<>();for(Map.Entry<Byte, String> entry:huffList.entrySet()){newhuffList.put(entry.getValue(), entry.getKey());}//对应霍夫曼表转成字节,保存在list中ArrayList<Byte> arrayList = new ArrayList<Byte>();for(int i= 0; i<sb.length();) {int count= 1;boolean flag = true;Byte pdbyte = null;while(flag) {String substring = sb.substring(i, i+count);pdbyte = newhuffList.get(substring);if(pdbyte== null) {count++;}else {flag= false;}}i+=count;arrayList.add(pdbyte);}//将list转成数组byte[] bytes = new byte[arrayList.size()];for(int i=0; i<arrayList.size(); i++) {bytes[i]= arrayList.get(i);}return bytes;}/*** 霍夫曼编码* @param bytes* @return*/private static byte[] huffmanZip(byte[] bytes) {//统计各字符出现的次数,转化成树节点listList<Node> nodes = getNodes(bytes);//构建霍夫曼树Node hufTree = createHuffmanTree(nodes); //创建霍夫曼编码表Map<Byte, String> hufListMap = createHuffmanList(hufTree);//编码byte[] code = zip(bytes, hufListMap);return code;}/*** 按照霍夫曼表去编码字符串* @param bytes* @param hufListMap* @return*/private static byte[] zip(byte[] bytes, Map<Byte, String> hufListMap) {//创建一个变量来存储字符对应的霍夫曼码StringBuilder sb= new StringBuilder();for(byte b :bytes) {sb.append(hufListMap.get(b));}//确定转出的2进制数对应多少个字节int length;if(sb.length()%8==0) {length = sb.length()/8;}else {length = sb.length()/8+1;}//每8个为一组,多余的另算byte zipbytes[] = new byte[length];int index = 0;for(int i=0; i<sb.length(); i+=8) {String strByte;if(i+8>sb.length()) {strByte = sb.substring(i);}else {strByte = sb.substring(i, i+8);}zipbytes[index] = (byte)Integer.parseInt(strByte, 2);index++;}return zipbytes;}//存储暂时路径的变量static StringBuilder sb = new StringBuilder();//用于存储赫夫曼编码static Map<Byte, String> huffList= new HashMap<>();/*** 将霍夫曼树转成霍夫曼编码表* @param hufTree* @return* 输出霍夫曼树,输出霍夫曼表* 若空,返回;若有,遍历左,给路径加0,遍历右,给路径加1;* 递归至叶节点,保存霍夫曼表*/private static Map<Byte, String> createHuffmanList(Node hufTree) {if(hufTree==null) {return null;}else {//处理霍夫曼树的左子树transferToList(hufTree.left, "0", sb);//处理霍夫曼树的右子树transferToList(hufTree.right, "1", sb);return huffList;}}private static void transferToList(Node node, String code, StringBuilder sb) {StringBuilder sb2  = new StringBuilder(sb);sb2.append(code);if(node.data==null) {//非叶节点transferToList(node.left, "0", sb2);transferToList(node.right, "1", sb2);}else {huffList.put(node.data, sb2.toString());}}/*** 创建赫夫曼树* @param nodes* @return*/private static Node createHuffmanTree(List<Node> nodes) {while(nodes.size()>1) {//按树中的value排序Collections.sort(nodes);//System.out.println(nodes);//取出、合并最小的两个树Node little1 = nodes.get(nodes.size()-1);Node little2 = nodes.get(nodes.size()-2);Node newNode = new Node(null, (little1.weight+little2.weight));//原2个二叉树为新创建的子树newNode.left = little1;newNode.right = little2;//移除最小的两个树nodes.remove(little1);nodes.remove(little2);//将合并后的树加入集合,重新排序(循环)nodes.add(newNode);}return nodes.get(0);}/*** 将字节转成List* @param bytes* @return    存储node的List*/private static List<Node> getNodes(byte[] bytes) {List<Node> nodes = new ArrayList<>();//存储每一个字符及出现次数Map<Byte, Integer> counts = new HashMap<>();//遍历有哪些字符,并记录数量for(byte b: bytes) {if(counts.get(b)==null) {counts.put(b, 1);}else {counts.put(b, counts.get(b)+1);}}//将每一个enter转成一个node,放入list中for(Map.Entry<Byte, Integer> entry: counts.entrySet()) {nodes.add(new Node(entry.getKey(), entry.getValue()));}return nodes;}}

树节点创建代码:

package demo10;public class Node implements Comparable<Node> {Byte data;int weight;Node left;Node right;public Node(Byte data,int weight) {this.data=data;this.weight=weight;}@Overridepublic String toString() {return "Node [data=" + data + ", weight=" + weight + "]";}@Overridepublic int compareTo(Node o) {return o.weight-this.weight;}
}

数据结构与算法之霍夫曼编码解码实现相关推荐

  1. 霍夫曼算法_霍夫曼编码算法

    霍夫曼算法 In this tutorial, we'll be discussing and implementing the Huffman Coding Algorithm in Java. 在 ...

  2. 加密与压缩,霍夫曼编码解码

    简介: 通过统计一篇文章(或一本书)中每个字符出现的频率(比如字母a出现了100次),对文中出现的每个字符进行编码. 这种编码的特点是出现频率越高的字符,其编码长度越短. 有了这样的字符.编码对照表, ...

  3. Zlib压缩算法:LZ77、LZ78、霍夫曼编码、滑动窗口、Rabin-Karp算法、哈希链、I/O缓冲区

    Table of Contents 1.简介 1.1 什么是zlib 2.压缩算法 2.1 放气 2.2 LZ77 2.2.1 滑动窗口 2.2.2 长距离对 2.3 霍夫曼编码 3. zlib的实现 ...

  4. 数据结构与算法 / 霍夫曼树、霍夫曼编码和解码

    一. 诞生原因 找出存放一串字符所需的最少的二进制编码. 二. 构造方法 首先统计出每种字符出现的频率,即:概率.权值. 例如:频率表 A:60,    B:45,   C:13   D:69   E ...

  5. 哈夫曼编码压缩率计算_程序员的算法课(8)-贪心算法:理解霍夫曼编码

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/ ...

  6. 程序员的算法课(8)-贪心算法:理解霍夫曼编码

    一.一种很贪婪的算法定义 贪心是人类自带的能力,贪心算法是在贪心决策上进行统筹规划的统称. [百度百科]贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体 ...

  7. 【数据结构】图解霍夫曼编码,看了就能懂

    今天来给大家普及一下霍夫曼编码(Huffman Coding),一种用于无损数据压缩的熵编码算法,由美国计算机科学家大卫·霍夫曼在 1952 年提出--这么专业的解释,不用问,来自维基百科了. 说实话 ...

  8. C语言Huffman Encode霍夫曼编码的算法(附完整源码)

    C语言Huffman Encode霍夫曼编码的算法 C语言Huffman Encode霍夫曼编码的算法完整源码(定义,实现,main函数测试) C语言Huffman Encode霍夫曼编码的算法完整源 ...

  9. 贪心算法之最小堆实现霍夫曼编码

    贪心算法之最小堆实现霍夫曼编码 实现之前需要学习的地方: 如果你不了解堆.堆的插入.堆的删除,可以先看下我前面几篇博客 http://blog.csdn.net/u011068702/article/ ...

最新文章

  1. 在WebStorm里面搜索文件中出现的中文字符
  2. NSIS 的 Modern UI 教程(二)
  3. 编译器角度看C++复制构造函数
  4. Ruby on Rails 生成指定版本的 Rails 项目
  5. xtrabackup备份脚本
  6. cycleGAN的整体架构+损失函数理解
  7. elasticsearch RestHighLevelClient 使用方法及封装工具
  8. Eclipse启动tomcat项目乱码而终端启动tomcat正常的解决办法
  9. Eclipse编译时函数报错:Undefined reference to 'pthread_create'
  10. poj 2253 Frogger floyd 长路求权值最大边,属于简单题!!!!
  11. 合成器插件Serum 1.23b7绿化版亲测有效
  12. 唐诗三百首加密软件如何使用_绿盾加密软件如何设置审批流程管理
  13. 智慧环保 | 云计算护航环保行业未来可期
  14. 将无线鼠标改造成有线鼠标
  15. JVM垃圾收集器详解之Parallel Scavenge
  16. 下载微信公众号中的视频的方法
  17. 北京国家会计学院聂兴凯:用友BIP事项会计助力企业迈入智能会计时代
  18. 关于计算机未来理想,坚持理想向往未来的励志说说
  19. 中国求职者2亿私人简历泄露,APT情报资讯报告2018全球十大安全事件(10401字) (附PDF公号发“简历十大安全”下载)
  20. 腾讯QQ大数据:机器学习建模问题中的特征构造方法

热门文章

  1. 从 RequireJs 源码剖析脚本加载原理
  2. Python链接Sql server
  3. VMware中网络设置之host-only
  4. MFC多国语言——资源副本
  5. psql: 致命错误: 用户 postgres Ident 认证失败
  6. 在程序开发中怎样写SQL语句可以提高数据库的性能
  7. ESFramework介绍之(34)―― ITcpServerAgent和IUdpServerAgent组件关系图
  8. SuseLinux详解(2)——网络设置静态IP 网关 DNS的方法
  9. SELinux系列(四)——SELinux配置文件(/etc/selinux/config)详解
  10. vnpy学习_02各文件功能梳理