huffman编码的程序流程图_Huffman编码实现压缩解压缩

这是我们的课程中布置的作业。找一些资料将作业完毕,顺便将其写到博客,以后看起来也方便。

原理介绍

什么是Huffman压缩

Huffman( 哈夫曼 ) 算法在上世纪五十年代初提出来了,它是一种无损压缩方法,在压缩过程中不会丢失信息熵。并且能够证明 Huffman 算法在无损压缩算法中是最优的。

Huffman 原理简单,实现起来也不困难,在如今的主流压缩软件得到了广泛的应用。

相应用程序、重要资料等绝对不同意信息丢失的压缩场合, Huffman 算法是非常好的选择。

怎么实现Huffman压缩

哈夫曼压缩是个无损的压缩算法,一般用来压缩文本和程序文件。哈夫曼压缩属于可变代码长度算法一族。意思是个体符号(比如,文本文件里的字符)用一个特定长度的位序列替代。

因此。在文件里出现频率高的符号,使用短的位序列。而那些非常少出现的符号。则用较长的位序列。

二叉树

在计算机科学中。二叉树是每个结点最多有两个子树的有序树。

通常子树的根被称作 “ 左子树 ” ( left subtree )和 “ 右子树 ” ( right subtree )。

哈夫曼编码 (Huffman Coding)

哈夫曼编码是一种编码方式,哈夫曼编码是可变字长编码 (VLC) 的一种。 uffman 于 1952 年提出一种编码方法。该方法全然依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就叫作 Huffman 编码。

Huffman编码生成步骤

扫描要压缩的文件,对字符出现的频率进行计算。

把字符按出现的频率进行排序,组成一个队列。

把出现频率最低(权值)的两个字符作为叶子节点。它们的权值之和为根节点组成一棵树。

把上面叶子节点的两个字符从队列中移除,并把它们组成的根节点增加到队列。

把队列又一次进行排序。反复步骤 3、4、5 直到队列中仅仅有一个节点为止。

把这棵树上的根节点定义为 0 (可自行定义 0 或 1 )左边为 0 。右边为 1 。

这样就能够得到每个叶子节点的哈夫曼编码了。

如 (a) 、 (b) 、 (c) 、 (d) 几个图,就能够将离散型的数据转化为树型的了。

假设假设树的左边用0 表示右边用 1 表示。则每个数能够用一个 01 串表示出来。

则能够得到相应的编码例如以下:

1–>110

2–>111

3–>10

4–>0

每个01 串,既为每个数字的哈弗曼编码。

为什么能压缩

压缩的时候当我们遇到了文本中的1 、 2 、 3 、 4 几个字符的时候,我们不用原来的存储,而是转化为用它们的 01 串来存储不久是能减小了空间占用了吗。(什么 01 串不是比原来的字符还多了吗?怎么降低?)大家应该知道的。计算机中我们存储一个 int 型数据的时候一般式占用了 2^32-1 个 01 位,由于计算机中全部的数据都是最后转化为二进制位去存储的。所以。想想我们的编码不就是仅仅含有 0 和 1 嘛,因此我们就直接将编码依照计算机的存储规则用位的方法写入进去就能实现压缩了。

比方:

1这个数字。用整数写进计算机硬盘去存储,占用了 2^32-1 个二进制位

而假设用它的哈弗曼编码去存储,仅仅有110 三个二进制位。

效果显而易见。

编码实现

流程图

编码流程

Created with Raphaël 2.1.0開始读入待压缩文件,计算文件里各字符的权重依据权重构建Huffman树依据Huffman树获得各个字符的HUffman编码,并建立Huffman编码的HashTable将字符总数、字符种数,以及Huffman树写入压缩文件文件头再次读入待压缩文件。依据其内容和coding hash table 将压缩后的数据写入文件结束

数据结构

CharacterWeight:记录字符值。以及其在待压缩文件里的权重。

public class CharacterCode {

private int weight;//字符值

private char character;//字符值

private String code;//其相应huffman编码

}

HuffmanNode:huffman树中的节点信息。

public class HuffmanNode {

private int parent;//父节点

private int lChild;//左子

private int rChild;//右子

private int weight;//权重

}

程序关键步骤

Huffman树的构建

Huffman树的变量:ArrayList list;

流程图

Created with Raphaël 2.1.0開始i=0n=字符的种数循环遍历查找列表中权重最小的两个node创建一个新的节点作为找到的两个权重最小的节点的父节点,并将该父节点的权重置为权重最小的两节点的权重和。将该节点增加数组中。

i++i

代码

for(int i=0;i

//w1 : the first min weight w2: the second min weight

//i1 : the first min weight index, i2: the second min weight index

int w1 = MAX_VALUE, w2=MAX_VALUE;

int i1 = 0, i2 = 0;

// find the two node with the minimum weight

for(int j=0;j

HuffmanNode node = tree.get(j);

if(node.getWeight()< w1 && node.getParent()==-1){

w2 = w1;

w1 = node.getWeight();

i2 = i1;

i1 = j;

}

else if(node.getWeight()

w2 = node.getWeight();

i2 = j;

}

}

//set the two node to be the children of a new node, and add the new node to the tree

HuffmanNode pNode = new HuffmanNode(w1+w2);

pNode.setlChild(i1);

pNode.setrChild(i2);

tree.add(pNode);

tree.get(i1).setParent(tree.indexOf(pNode));

tree.get(i2).setParent(tree.indexOf(pNode));}

依据Huffman 树获得Huffman编码

从叶子节点開始网上遍历Huffman树,直到到达根节点,依据当前节点为其父节点的左儿子还是右儿子确定这一位值是0还是1。最后将依次获得的0,1字符串反转获得Huffman编码。

for(int i=0;i

HuffmanNode node = tree.get(i);

HuffmanNode pNode = tree.get(node.getParent());

String code ="";

while(true){

if(pNode.getlChild()==tree.indexOf(node)){

code = "0"+code;

}

else if(pNode.getrChild() == tree.indexOf(node)){

code = "1"+code;

}

else {

System.out.println("Tree Node Error!!!");

return null;

}

node=pNode;

if(node.getParent()!=-1)

pNode=tree.get(node.getParent());

else

break;

}

list.get(i).setCode(new String(code));

}

头文件设计

编码

类型

字节数

字符总数

Int

4

字符种类数

Short

2

叶子节点

char字符 short 父节点

3

非叶子节点

Short 左儿子 short 右儿子 short父节点

6

文件头长度(单位: byte)

l= 9n

当中n 为字符种类数。

文件内容的编码和写入

Created with Raphaël 2.1.0開始将待压缩文件读入字符数组依据coding hash table 获得huffman编码字符串,并将该字符串增加到buff中查看buff,假设字符数大于8则将字符串转换为Short类型变量并写入文件将写入的字符从buff中删除是否到达文件尾?结束yesno

代码

while((temp=reader.read())!=-1){//!= EOF

// get the code from the code table

String code = codeTable.get((char)temp);

c++;

if(c>=count/96){

System.out.print("=");

c=0;

}

try{

StringBuilder codeString = new StringBuilder(code);

outputStringBuffer.append(codeString);

while(outputStringBuffer.length()>8){

out.write(Short.parseShort(outputStringBuffer.substring(0, 8),2));

outputStringBuffer.delete(0, 8);

}

} catch(Exception e){

e.printStackTrace();

}

}

解码实现

流程图

Created with Raphaël 2.1.0開始读压缩文件。读入文件头,获得字符总数。字符种数以及huffman表信息。重建huffman树读入正文,依据重建得到的huffman树获得原本的字符。将字符写入解压缩后的文件是否到达文件尾部?结束yesno

数据结构

HuffmanNode:huffman树中的节点信息。

public class HuffmanNode {

private int parent;//父节点

private int lChild;//左子

private int rChild;//右子

private int weight;//权重

}

程序关键步骤

重建Huffman树。

在文件头中存放的原本就是Huffman树的节点信息。

in = new DataInputStream(new FileInputStream(file));

count = in.readInt();

charNum = in.readShort();

nodeNum = 2*charNum -1;

//rebuild the huffman tree

for(int i=0;i

HuffmanNode node = new HuffmanNode((char)in.readByte());

int parent = in.readShort();

node.setParent(parent);

tree.add(node);

}

for(int i=charNum;i

HuffmanNode node = new HuffmanNode(' ');

int l = in.readShort();

int r = in.readShort();

int p = in.readShort();

node.setlChild(l);

node.setrChild(r);

node.setParent(p);

tree.add(node);

}

解码

流程图

Created with Raphaël 2.1.0開始Buff.length<32从文件里读入整数将读入的整数转为二进制字符串,并将其加到buff中依据buff中的01字符从顶向下遍历huffman树。得到叶子节点、其相应的解码值,将其写入文件,从buff中遍历删去已经遍历过的字符字符数是否达到总数处理buff中剩余内容结束yesnoyesno

代码

while(true){

while(buff.length()<32){

temp = in.readInt();

String codeString = Integer.toBinaryString(temp);

while(codeString.length()<32){

codeString='0'+codeString;

}

buff.append(codeString);

}

node = tree.get(tree.size()-1);

dep = 0;

while(!(node.getlChild()==-1&&node.getrChild()==-1)){

if(dep>=buff.length()){

System.out.println( "Buff overflow");

}

if(buff.charAt(dep)=='0'){

node = tree.get(node.getlChild());

}

else if(buff.charAt(dep)=='1'){

node = tree.get(node.getrChild());

}

else{

System.out.println("Coding error");

}

dep++;

}

char c = node.getCH();

num++;

if(num>=n/99){

System.out.print("=");

num=0;

}

count++;

if(count>=n){

break;

}

charBuff+=c;

if(charBuff.length()>256){

writer.write(charBuff);

charBuff="";

}

buff.delete(0, dep);

}

} catch(EOFException e){

//just do nothing

}

catch(Exception e){

e.printStackTrace();

} finally{

//there may be data released in the buff and charbuff, so we need to process them

while(buff.length()>0){

node = tree.get(tree.size()-1);

dep = 0;

while(!(node.getlChild()==-1&&node.getrChild()==-1)){

if(dep>=buff.length()){

break;

}

if(buff.charAt(dep)=='0'){

node = tree.get(node.getlChild());

}

else if(buff.charAt(dep)=='1'){

node = tree.get(node.getrChild());

}

else{

System.out.println("Coding error");

//return;

}

dep++;

}

char c = node.getCH();

num++;

if(num>=n/99){

System.out.print("=");

num=0;

}

count++;

if(count>=n){

break;

}

charBuff+=c;

if(charBuff.length()>256){

try {

writer.write(charBuff);

} catch (IOException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

charBuff="";

}

buff.delete(0, dep);

}

try {

writer.write(charBuff);

writer.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

try{

writer.close();

} catch(IOException e){

throw e;

}

项目源代码

留坑回头放上

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355251.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

solr创建索引_Solr:创建拼写检查器

solr创建索引在上一篇文章中&#xff0c;我谈到了Solr Spellchecker的工作原理&#xff0c;然后向您展示了其性能的一些测试结果。 现在&#xff0c;我们将看到另一种拼写检查方法。 与其他方法一样&#xff0c;此方法使用两步过程。 相当快速的“候选单词”选择&#xff0c;然…

5000元性价比高的笔记本_2018性价比笔记本电脑品牌推荐 5000左右笔记本性价比推荐...

对于年年都出新款的电子产品&#xff0c;购买者们每年都经历一回挑花眼的时刻&#xff0c;那2018有什么笔记本比较好呢?宏碁暗影骑士3参考价&#xff1a;5099元内存容量&#xff1a;8G  显存容量&#xff1a;2G  硬盘容量&#xff1a;128G1T显卡型号&#xff1a;GTX1050(高…

Hibernate模糊查询

Hibernate模糊查询1.不使用hql DetachedCriteria criteria DetachedCriteria.forClass(User.class);if (StringUtils.isNotEmpty(yh)) {criteria.add(Restrictions.or(Restrictions.eq("yhid", yh),Restrictions.like("yhxm", yh, MatchMode.ANYWHERE)))…

带有Javaslang的Java 8中的功能数据结构

Java 8的lambda&#xff08;λ&#xff09;使我们能够创建出色的API。 它们令人难以置信地提高了语言的表达能力。 Javaslang利用lambda来基于功能模式创建各种新功能。 其中之一是功能性集合库&#xff0c;旨在替代Java的标准集合。 &#xff08;这只是鸟瞰图&#xff0c;您…

丰田pcs可以关闭吗_丰田车必备的配置有哪些是在亚洲龙上体现了?

亚洲龙基于丰田TNGA架构下的GA-K平台打造而来&#xff0c;与雷克萨斯ES一致&#xff0c;先期推出搭载2.5L自然吸气发动机以及2.5L混合系统的车型。作为一汽丰田的全新旗舰轿车&#xff0c;亚洲龙主销车型配备丰田TSS规避碰撞辅助套装&#xff0c;英文全拼为 “Toyota Safety Se…

[NOIP2014]飞扬的小鸟

思路{ 对于每一列&#xff0c;小鸟或下落&#xff0c;或上升。那我们很容易想到对应的背包问题&#xff01; 按照完全背包的思想更新上升部分&#xff0c;01背包的方法更新下降部分。 撞到柱子了(aluba。。。。。。aluba.。。。。。)不慌&#xff0c;只需把它设为不可打即可&am…

2020 dns排名_2020年新版全球/全国各地ISP的DNS服务器地址表

【第一】国内外知名的公共DNS服务器(排列不分先后)&#xff1a;腾讯公共DNS(119.29.29.29、182.254.116.116)阿里公共DNS(223.5.5.5、223.6.6.6)百度公共DNS(180.76.76.76)360安全DNS(123.125.81.6)Google(8.8.8.8、8.8.4.4)114DNS(114.114.114.114、114.114.115.115)OpenDNS(2…

Spring MVC 登录拦截器

Spring MVC 登录拦截器1.编写拦截器 package interceptor;import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRespons…

bzoj1556 (DP)

bzoj 1556 点这里打开题目 题目是求 a^2 求和&#xff1b; 原问题可以转化为&#xff1a;两个人在玩这个东西&#xff0c;问这两个人弄出来的序列相同的有多少种情况&#xff0c;操作方式不同即为一种不同的情况。 就这个问题&#xff0c;参考大佬的DP思想。 DP[t][i][j] 分别…

帆软参数设置_数据分析软件之FineReport教程:[5]参数界面JS(全)

在用报表工具设计报表时&#xff0c;使用参数控件时&#xff0c;有时我们希望部分参数控件在没满足条件时不显示&#xff0c;满足条件后再显示&#xff0c;接下来我就来教教大家怎么做&#xff01;表格软件如何根据条件控制参数控件是否显示一&#xff1a;问题描述在使用参数控…

wurfl_比较OpenDDR与WURFL

wurfl量身定制的Web内容通常受益于定制&#xff0c;以考虑多种因素&#xff0c;例如屏幕大小&#xff0c;标记语言支持和图像格式支持。 此类信息存储在“设备描述存储库”&#xff08;DDR&#xff09;中。 WURFL和OpenDDR项目都提供了访问DDR的API&#xff0c;以简化并促进适应…

ssm 静态资源处理器

ssm 静态资源处理器<!-- 静态资源处理--><mvc:default-servlet-handler/>

极简单的方式序列化sqlalchemy结果集为JSON

继承 json.JSONEncoder 实现一个针对sqlalchemy返回类型的处理方式。 sqlalchemy的返回类型有大都有两种&#xff0c;一种是Model对象&#xff0c;一种是Query集合&#xff08;只查询部分字段&#xff09;。 针对这两种返回结果&#xff0c;都是来自同一中类型 sqlalchemy.orm…

easymock 图片_数据模拟神器 easy-mock 正式开源

开源公告由大搜车无线团队出品的 easy-mock 在线数据模拟服务上线至今已经有几个月时间了&#xff0c;近期网站刚更新了焕然一新的 2.0 版本&#xff0c;与此同时&#xff0c;我们还带来一个更重磅的消息&#xff1a;今天正式将整个服务的代码在 github 开源(github.com/easy-m…

在自定义Java 9映像上运行Eclipse Neon

我已经开始修改自定义Java二进制运行时映像文件。 映像文件是打包为运行时平台的模块的配置。 基本上&#xff0c;默认映像包含组成Java运行时的所有内容。 自定义图像可以包含该图像的一些子集。 例如&#xff0c;我创建了一个仅包含“ compact 3”概要文件的映像&#xff0c…

ssm异常捕获和处理

ssm异常捕获和处理package exception;import lombok.extern.slf4j.Slf4j; import org.hibernate.HibernateException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ResponseBody; import entity.vo.Res…

载波聚合或双连接的方式进行_处理载波聚合及双连接的装置及方法与流程

本发明涉及一种用于无线通信系统的通信装置及方法&#xff0c;尤其涉及一种处理载波聚合及双连接的装置及方法。背景技术&#xff1a;通过第三代合作伙伴计划(third generation partnership project&#xff0c;3GPP)发起的新无线(new radio&#xff0c;NR)系统包含有新无线接口…

拼接xml

拼接xml/*** description 拼接xml* param list 用户信息* return java.lang.String 拼接完成的xml* author zhaohuaqing* date 2021/6/21 15:39* version 1.0*/public static String getUserXMl(List<User> list,int totalNumber,int start){StringBuilder sb new Stri…

unity游戏开发毕设_一个程序小白的unity 2D游戏开发的反思与经验

学游戏设计的码农&#xff0c;中传大三在校生&#xff0c;代码水平目前还在进阶中。这个学期和美术一起进行了一次不成熟的磕磕绊绊的游戏开发。踩了很多坑&#xff0c;就当是毕设前的预热吧&#xff0c;做个总结&#xff0c;希望毕设不会再犯这些错误。因为整个本科阶段做的或…

Asp.Net MVC项目通过Git同步到新开发设备上后无法作为网站启动

右键项目名->属性->启动项目->单启动项目&#xff0c;在下拉框中选择你的网站主项目就可以了。&#xff08;由于用的英文版&#xff0c;所以翻译的内容可能略有差异&#xff09;转载于:https://www.cnblogs.com/chenyangsocool/p/7127469.html