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

原理介绍

  • 什么是Huffman压缩

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

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

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

  • 怎么实现Huffman压缩

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

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

    1. 二叉树

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

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

    2. 哈夫曼编码 (Huffman Coding)

      哈夫曼编码是一种编码方式,哈夫曼编码是可变字长编码 (VLC) 的一种。 uffman 于 1952 年提出一种编码方法。该方法全然依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就叫作 Huffman 编码。
  • Huffman编码生成步骤
    1. 扫描要压缩的文件,对字符出现的频率进行计算。
    2. 把字符按出现的频率进行排序,组成一个队列。
    3. 把出现频率最低(权值)的两个字符作为叶子节点。它们的权值之和为根节点组成一棵树。
    4. 把上面叶子节点的两个字符从队列中移除,并把它们组成的根节点增加到队列。
    5. 把队列又一次进行排序。反复步骤 3、4、5 直到队列中仅仅有一个节点为止。

    6. 把这棵树上的根节点定义为 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 三个二进制位。

    效果显而易见。

编码实现

  1. 流程图

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

    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;//权重
}
  1. 程序关键步骤

    • Huffman树的构建

      Huffman树的变量:ArrayList list;

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

i++i<n-1结束yesno

代码

for(int i=0;i<list.size()-1;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<tree.size();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.getParent()==-1){
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<list.size();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<charNum;i++){
      HuffmanNode node = new HuffmanNode((char)in.readByte());
      int parent = in.readShort();
      node.setParent(parent);
      tree.add(node);
      } for(int i=charNum;i<nodeNum;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://blog.csdn.net/u010485034/article/details/30750245

http://blog.sina.com.cn/s/blog_694448320100nd5v.html

Huffman编码实现压缩解压缩的更多相关文章

  1. Huffman编码和解码

    一.Huffman树 定义: 给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径达到最小,这样的二叉树称为最优二叉树,也称为霍夫曼树(Huffman树). 特点:     Huffman树 ...

  2. Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序

    前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的re ...

  3. Huffman编码实现文件的压缩与解压缩。

    以前没事的时候写的,c++写的,原理很简单,代码如下: #include <cstdio> #include <cstdlib> #include <iostream&g ...

  4. 【13】MD5编码、Zlib压缩解压缩

    1.MD5加密 /// <summary> /// 使用MD5加密算法 /// </summary> /// <param name="md5MessageSt ...

  5. [老文章搬家] 关于 Huffman 编码

    按:去年接手一个项目,涉及到一个一个叫做Mxpeg的非主流视频编码格式,编解码器是厂商以源代码形式提供的,但是可能代码写的不算健壮,以至于我们tcp直连设备很正常,但是经过一个UDP数据分发服务器之后 ...

  6. 【数据压缩】Huffman编码

    1. 压缩编码概述 数据压缩在日常生活极为常见,平常所用到jpg.mp3均采用数据压缩(采用Huffman编码)以减少占用空间.编码\(C\)是指从字符空间\(A\)到码字表\(X\)的映射.数据压缩 ...

  7. huffman 编码

    huffman压缩是一种压缩算法,其中经典的部分就是根据字符出现的频率建立huffman树,然后根据huffman树的构建结果标示每个字符.huffman编码也称为前缀编码,就是每个字符的表示形式不是 ...

  8. Huffman 编码压缩算法

    前两天发布那个rsync算法后,想看看数据压缩的算法,知道一个经典的压缩算法Huffman算法.相信大家应该听说过 David Huffman 和他的压缩算法—— Huffman Code,一种通过字 ...

  9. [转载]Huffman编码压缩算法

    转自http://coolshell.cn/articles/7459.html 前两天发布那个rsync算法后,想看看数据压缩的算法,知道一个经典的压缩算法Huffman算法.相信大家应该听说过 D ...

随机推荐

  1. Elasticsearch之curl删除索引库

    关于curl创建索引库的介绍,请移步 Elasticsearch之curl创建索引库 [hadoop@djt002 elasticsearch-2.4.3]$ curl -XPUT 'http://1 ...

  2. mysql Workbench新建数据库连接时提示SSl not enabled的问题

    在使用workbench时会弹出以下的对话框,不过这不影响使用,点击ok之后对话框关闭,接着直接点击close就行了,之后会显示已经连接上了数据库.具体ssl的方面还没研究,等研究了再贴

  3. 4 Things I Wish I Would Have Known When I Started My Software Development Career【当我最开始从事软件工程师的时候我希望我知道的四件事】

    英文原文:http://simpleprogrammer.com/2013/08/19/software-development-career/ My software development car ...

  4. System.Web.Caching.Cache类 Asp.Net缓存 各种缓存依赖

    Cache类,是一个用于缓存常用信息的类.HttpRuntime.Cache以及HttpContext.Current.Cache都是该类的实例. 一.属性 属性 说明 Count 获取存储在缓存中的 ...

  5. Deutsch lernen (10)

    Dieser Weg Dieser Weg wird kein leichter sein. Dieser Weg wird steinig und schwer. Nicht mit vielen ...

  6. SAP computer之program counter

    Program counter The program is stored in memory with the first instruction at binary address 0000, t ...

  7. 【技术累积】【点】【Java】【12】几种常见编码(持续更新)

    问题描述 有这么一段代码: String question = new String(record.getQuestion().getBytes("iso-8859-1"), &q ...

  8. 07--c++类的构造函数详解

    c++类的构造函数详解 c++构造函数的知识在各种c++教材上已有介绍,不过初学者往往不太注意观察和总结其中各种构造函数的特点和用法,故在此我根据自己的c++编程经验总结了一下c++中各种构造函数的特 ...

  9. python迭代器,生成器,推导式

    可迭代对象 字面意思分析:可以重复的迭代的实实在在的东西. list,dict(keys(),values(),items()),tuple,str,set,range, 文件句柄(待定) 专业角度: ...

  10. 51nod1046 A^B Mod C【快速幂】

    给出3个正整数A B C,求A^B Mod C. 例如,3 5 8,3^5 Mod 8 = 3. Input 3个正整数A B C,中间用空格分隔.(1 <= A,B,C <= 10^9) ...