20172311-哈夫曼编码测试

哈夫曼编码与哈夫曼树

  • 哈夫曼树
    哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的带权路径长度记为WPL= (W1L1+W2L2+W3L3+...+WnLn),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明哈夫曼树的WPL是最小的。

  • 哈夫曼编码
    哈夫曼编码(HuffmanCoding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。uffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就叫作Huffman编码。哈夫曼编码是一种无前缀编码。解码时不会混淆。其主要应用在数据压缩,加密解密等场合。

哈夫曼编码步骤

1、对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。(为方便在计算机上实现算法,一般还要求以Ti的权值Wi的升序排列。)
2、在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。
3、从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。
4、重复二和三两步,直到集合F中只有一棵二叉树为止。

举例如下:

假如我有A,B,C,D,E五个字符,出现的频率(即权值)分别为5,4,3,2,1,那么我们第一步先取两个最小权值作为左右子树构造一个新树,即取1,2构成新树,其结点为1+2=3,如图:

虚线为新生成的结点,第二步再把新生成的权值为3的结点放到剩下的集合中,所以集合变成{5,4,3,3},再根据第二步,取最小的两个权值构成新树,如图:

再依次建立哈夫曼树,如下图:

其中各个权值替换对应的字符即为下图:

所以各字符对应的编码为:A->11,B->10,C->00,D->011,E->010

用Java实现哈夫曼编码

  • 创建哈夫曼树的结点类

该结点类中包括哈夫曼树的父节点,左孩子和右孩子;权值以及char类型的元素(存放26个英文字母用)。代码如下:

//哈夫曼树的节点类
public class huffmanNode implements Comparable<huffmanNode>
{private int weight;private huffmanNode parent,left,right;private char element;public huffmanNode(int weight, char element , huffmanNode parent, huffmanNode left, huffmanNode right) {this.weight = weight;//权值this.element = element;//char元素this.parent = parent;//父节点this.left = left;//左孩子this.right = right;//右孩子}public int getWeight() {return weight;}@Overridepublic int compareTo(huffmanNode huffmanNode) {return this.weight - huffmanNode.getWeight();}public huffmanNode getParent() {return parent;}public void setParent(huffmanNode parent) {this.parent = parent;}public huffmanNode getLeft() {return left;}public void setLeft(huffmanNode left) {this.left = left;}public huffmanNode getRight() {return right;}public void setRight(huffmanNode right) {this.right = right;}public char getElement() {return element;}public void setElement(char element) {this.element = element;}
}      
  • 创建哈夫曼树类

    1.编写构造函数,接收一个哈夫曼节点类的数组,使用最小堆生成相应的哈夫曼树。构造函数如下:

public huffmanTree(huffmanNode[] huffmanArray) {huffmanNode parent = null;SmallArrayHeap<huffmanNode> heap = new SmallArrayHeap<>();for (int i=0;i<huffmanArray.length;i++){heap.addElement(huffmanArray[i]);}for(int i=0; i<huffmanArray.length-1; i++) {huffmanNode left = heap.removeMin(); //左孩子是最小节点huffmanNode right = heap.removeMin();parent = new huffmanNode(left.getWeight()+right.getWeight(),' ',null,left,right);left.setParent(parent);right.setParent(parent);heap.addElement(parent);}root = parent;}    

2.编写一个哈夫曼树的中序遍历方法用于得到基本元素的编码的数组,中序遍历方法如下:

 protected void inOrder( huffmanNode node,ArrayList<huffmanNode> tempList){if (node != null){inOrder(node.getLeft(), tempList);if (node.getElement()!=' ')tempList.add(node);inOrder(node.getRight(), tempList);}}  

3.利用无序列表和栈以及中序遍历方法实现得到需要的基本元素的编码的数组的方法,方法如下:

 public String[] getEncoding() {ArrayList<huffmanNode> arrayList = new ArrayList();inOrder(root,arrayList);for (int i=0;i<arrayList.size();i++){huffmanNode node = arrayList.get(i);String result ="";int x = node.getElement()-'a';Stack stack = new Stack();while (node!= root){if (node==node.getParent().getLeft())stack.push(0);if (node==node.getParent().getRight())stack.push(1);node=node.getParent();}while (!stack.isEmpty()){result +=stack.pop();}codes[x] = result;}return codes;}  
  • 使用哈夫曼树编码解码测试

1.读取文件,并打印文件中各字母出现的频率,代码如下:

File file = new File("C:\\Users\\user\\IdeaProjects\\socialsea\\socialsea\\src\\HuffmanTest\\readFile");Scanner scan = new Scanner(file);String s = scan.nextLine();System.out.println(s);int[] array = new int[26];for (int i = 0; i < array.length; i++) {array[i] = 0;}for (int i = 0; i < s.length(); i++) {char x = s.charAt(i);array[x - 'a']++;}System.out.println("各字母出现频率:");for (int i = 0; i < array.length; i++) {System.out.print((char)('a'+i)+":"+(double) array[i] / s.length()+" ");}  

2.构造有26个字母元素的哈夫曼树,代码如下:

huffmanNode[] huffmanTreeNodes = new huffmanNode[array.length];for (int i = 0; i < array.length; i++) {huffmanTreeNodes[i] = new huffmanNode(array[i], (char) ('a' + i), null, null, null);}huffmanTree huffmanTree = new huffmanTree(huffmanTreeNodes);  

3.使用哈夫曼树类中getEncoding()方法得到a——z各字母对应的编码并打印出来。代码如下:

System.out.println("各字母的编码");String[] codes = huffmanTree.getEncoding();for (int i = 0; i < codes.length; i++) {System.out.println((char) ('a' + i) + ":" + codes[i]);}

4.对readFile文件中内容进行编码并输出,然后写入到codeResult文件中去,代码如下:

 //进行编码:String result = "";for (int i = 0; i < s.length(); i++) {int x = s.charAt(i) - 'a';result += codes[x];}System.out.println("编码结果:"+result);//写入文件File file1 = new File("C:\\Users\\user\\IdeaProjects\\socialsea\\socialsea\\src\\HuffmanTest\\codeResult");FileWriter fileWriter = new FileWriter(file1);fileWriter.write(result);fileWriter.close();

5.从codeResult文件中读取编码后的内容并解码,然后写入到decodeResult文件中,代码如下:

//从文件读取Scanner scan1 = new Scanner(file1);String s1 = scan1.nextLine();huffmanNode huffmanTreeNode = huffmanTree.getRoot();//进行解码String result2 = "";for (int i = 0; i < s1.length(); i++) {if (s1.charAt(i) == '0') {if (huffmanTreeNode.getLeft() != null) {huffmanTreeNode = huffmanTreeNode.getLeft();}} else {if (s1.charAt(i) == '1') {if (huffmanTreeNode.getRight() != null) {huffmanTreeNode = huffmanTreeNode.getRight();}}}if (huffmanTreeNode.getLeft() == null && huffmanTreeNode.getRight() == null) {result2 += huffmanTreeNode.getElement();huffmanTreeNode = huffmanTree.getRoot();}}System.out.println("解码结果:"+result2);//写入文件File file2 = new File("C:\\Users\\user\\IdeaProjects\\socialsea\\socialsea\\src\\HuffmanTest\\decodeResult");FileWriter fileWriter1 = new FileWriter(file2);fileWriter1.write(result2);fileWriter1.close();  

实验结果截图

  • readFile文件

  • codeResult文件

  • decodeResult文件

  • 运行结果

码云链接

感悟

刚开始的时候感觉通过哈夫曼树实现编码与解码肯定是非常复杂,首先每个字母对应的编码去怎么设计就好像无法完成,但是在学习的过程中逐渐发现其实也没有想象中那么难,把大的问题拆分开来,一步一步的去解决,最终就能将问题解决了,本次实验让我受益匪浅!

参考资料

  • 哈夫曼树与哈夫曼编码
  • 哈夫曼树(三)之 Java详解
  • 哈夫曼树(最优二叉树)及其Java实现
  • Java数据结构和算法:哈夫曼树
  • HaffManTree哈夫曼树的编码和解码的个人学习心得感悟

转载于:https://www.cnblogs.com/zhaoxiaohai/p/10110695.html

20172311-哈夫曼编码测试相关推荐

  1. 哈夫曼编码压缩解压缩实现不同类型文件压缩比的测试

    压缩原理及步骤&&压缩比的计算 压缩原理及步骤 压缩的第一步: 将一个文件以各个字符出现的次数为权值建立哈夫曼树,这样每个字符可以用从树根到该字符所在到叶子节点的路径来表示.(左为0, ...

  2. 哈夫曼编码 译码java_基于Java的哈夫曼编码译码系统_报告毕业论文

    基于Java的哈夫曼编码译码系统_报告毕业论文 1课 程 设 计Java 与面向对象程序设计课程设计基于 Java 的哈夫曼编码译码系统1.问题描述和分工情况1.1 问题描述使用 Java 语言实现哈 ...

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

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

  4. C++实现huffman哈夫曼编码的算法(附完整源码)

    C++实现huffman哈夫曼编码的算法 C++实现huffman哈夫曼编码的算法完整源码(定义,实现,main函数测试) C++实现huffman哈夫曼编码的算法完整源码(定义,实现,main函数测 ...

  5. 灵光一现的创造——霍夫曼编码

    点击上方"LiveVideoStack"关注我们 作者 | Alex 技术审校 | 赵军 霍夫曼 声影传奇 #004# 作为一名科学家和老师,我真的非常执着.如果我觉得自己还没有找 ...

  6. 数据结构(哈夫曼树,哈夫曼编码)入门篇,JAVA实现

    什么是哈夫曼树 哈夫曼树就是一种最优判定树,举个例子,如下一个判断逻辑 if(s<60) g=1; else if(s<70) g=2 else if(s<80) g=3 else ...

  7. 哈夫曼算法证明+哈夫曼编码译码程序实现

    哈夫曼算法证明 哈夫曼算法是一种贪心算法,我们考虑证明其最优子结构和贪心选择性质: 最优子结构:假设一个树是哈夫曼树,则以其任意节点为根节点的最大子树也是哈夫曼树. 证明:子树的根节点的值是其所有叶子 ...

  8. 树:哈夫曼树和哈夫曼编码的详细介绍以及代码实现

    闲扯前言 哈夫曼编码的代码实现对于初学数据结构的同学可能会有些困难,没有必要灰心,其实没啥,学习就犹如攀登一座又一座的山峰,每当我们攻克一个难点后,回首来看,也不过如此嘛.我们要做的就是不断的去攀越学 ...

  9. 哈夫曼编码(Huffman Coding)

    霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种. 霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符 ...

最新文章

  1. 2022-2028年中国演出市场深度调研与发展前景报告
  2. resnet50 自定义
  3. linux命令框显示中文乱码_CentOS终端命令行显示中文乱码的解决方法
  4. u-boot-1.1.6 设置新分区支持设备树
  5. 上云有风险 公有云选型小心进坑
  6. 卡巴斯基文件服务器,卡巴斯基更新服务器的解决方案
  7. 2021-05-19 Schur补引理及证明
  8. hls fifo_【正点原子FPGA连载】第一章HLS简介--领航者ZYNQ之HLS 开发指南
  9. 抓糗百数据和图片的Python爬虫
  10. feign 序列化_Spring Cloud Feign 配置 FastJson
  11. 未成年人可以申请贷款吗?
  12. jenkins安装(用户配置)(2)
  13. java应用程序多态_java – 多态和n层应用程序
  14. 程序员如何自制酒店 Wi-Fi?
  15. 系统学习深度学习(三十二)--Double DQN (DDQN)
  16. opencv实现超像素分割(slic实现)
  17. 简单说一下寄存器寻址
  18. 微信小程序退款 报错 FAIL 证书验证失败
  19. UE4 PBR材质使用记录
  20. 如何让电脑同时访问内网和外网:为电脑手动添加路由

热门文章

  1. Android bitmap图片处理
  2. Android Load Picture Asynchronously
  3. 程序员应知——学习、思考与分享
  4. 数据是互联网下半场产品人突围之道
  5. 99%的数据工作者不曾知道的一款利器
  6. 增长黑盒:零代码基础做智能电商网站,不要重复发明轮子
  7. WebStorm、PHPStorm、IntelliJ IDEA配置scss自动编译
  8. 设计模式(行为型模式)——访问者模式(Visitor)
  9. 转Python 参数知识(变量前加星号的意义)
  10. [转]Emacs 系列教程