`
杨杨和花花
  • 浏览: 21724 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

哈夫曼压缩的步骤

阅读更多
人一旦闲下来就很恐怖的,已经好久都没写博客了,热情也不如先前的。忙碌的时候,每做完一件事,我就一种自豪的感觉。我不想让自己活得很空虚。所以还得写点东西。
对于哈夫曼树,我们的解释是每次取出一组数组里的最小两个数来建树,把这两者的和放到
原先的数组。作为新的元素。重复以上操作,来建树。
以下的步骤只是我的理解
1.统计文件中字节出现的次数,并把次数作为结点来键哈夫曼树。
  如何来建树,这里出现了问题。我们实际是通过优先队列来进行建树的。这个队列里的数,
  按从小到大进行的排序,仿佛这个队列就是为哈夫曼树而生。
  统计次数的方法。
  public int[] FileRead(String path){
    //创建文件输入流
    try {
     FileInputStream  fils = new FileInputStream(path);
//将文件输入流包装成缓冲流
      BufferedInputStream fos=new BufferedInputStream(fils);
//读入字节
int a=fos.read();
while(a!=-1){
array[a]++;
//读取下一个字节
    a=fos.read();
}
} catch (Exception ef) {
ef.printStackTrace();
}
    return array;
     }
   建树的过程
    /** 
     * 通过优先队列来构造哈夫曼树,返回根结点
      */
    public TreeNode2 CreatTree(PriorityQueue<TreeNode2> list){
    while(list.size()>1){
    //取出两个构造
    TreeNode2 node1=list.poll();
    TreeNode2 node2=list.poll();
   
    //创建父结点
    TreeNode2 nodeparent=new TreeNode2();
        nodeparent.sum=node1.sum+node2.sum;
   
    list.add(nodeparent);
   
    //建立关系
    nodeparent.lchild=node1;
    node1.parent=nodeparent;
   
    nodeparent.rchild=node2;
    node2.parent=nodeparent;
   
    //给结点附哈夫曼编码
    node1.flag1=0;
    node2.flag1=1;
    }
    TreeNode2 lastnode=list.poll();
        return lastnode;
    }
  这里传入的参数优先队列,因为系统的优先队列不能排序根结点,所以需要自己重写其中
  的比较方法。
     /**
      * 将读入的数据存入优先队列
      */
     public PriorityQueue<TreeNode2> arraylist(int array[]){
    //根据指定的比较器创建一个优先队列
    PriorityQueue<TreeNode2> list = new PriorityQueue<TreeNode2>(11,new MyComparator());
    //将一个个结点对象存入到优先队列中
    for(int i=0;i<array.length;i++){
    if(array[i]!=0){
    TreeNode2 treenode=new TreeNode2();
    treenode.obj=i;
    treenode.sum=array[i];
    list.add(treenode);
    }
    }
    return list;
     }
     /**
      * 写一个类来是实现迭代器这个接口
      * @author Administrator
      *重写里面的方法compare
      */
    class MyComparator implements Comparator<TreeNode2>{
    public  int compare(TreeNode2 node1,TreeNode2 node2){
    int o1=node1.sum;
    int o2=node2.sum;
    return o1-o2;
    }
     }
2.通过哈夫曼树进行编码
    /**
     *
     * @param str对应一个节点的哈夫曼编码
     * @param root传入的根结点
     * @param code哈夫曼编码字符串数组
     */
    public void GetoneCode(String str,TreeNode2 root,String code[]){
    //首先判断节点是否为空
    if(root!=null){
    if(root.flag1!=null){
    str=str+root.flag1;
    if(root.lchild==null&&root.rchild==null){
    code[root.obj]=str;
    System.out.println(root.obj+"该字节"+"哈夫曼编码为"+str);
    //将找到的数据依次输入队列中
    Data data=new Data();
    data.str=str;
    data.obj=root.obj;
    list.add(data);
    }
    }
    //递归遍历
    TreeNode2 left=root.lchild;
    GetoneCode(str,left,code);
   
    TreeNode2 right=root.rchild;
    GetoneCode(str,right,code);
    }
    }
3.利用哈夫曼编码对应的字节来进行读文件,然后把01字符串每8个字符串写成一个字节。
/**
     * 文件压缩 并输出
     * 将得到的字符串数组,取出字符串每8位变成一个字节
     */
public void OutPut(String path,String oldpath){
//记录文件中的01字符串的个数
int num=0;
//记录文件补0的情况
int addzero=0;
try{
//创建输入流对象
FileInputStream fis=new FileInputStream(oldpath);
//创建输入缓冲流
BufferedInputStream dis=new BufferedInputStream(fis);
//创建输出流对象
FileOutputStream fos=new FileOutputStream(path);
//创建输出缓冲流
BufferedOutputStream dos=new BufferedOutputStream(fos);
   /**
    * 写头文件,文件内容最后补零的情况
    */
     dos.write(list.size());
     System.out.println("队列的长度"+list.size());
     for(int i=0;i<list.size();i++){
    Data data=list.get(i);
    dos.write(data.obj);
    byte by[]=data.str.getBytes();
    dos.write(by.length);
    dos.write(by);
    num+=array[data.obj]*data.str.length();
    }
         System.out.println("该数目为"+num);
         addzero=8-num%8;//求出添零的个数
         dos.write(addzero);
        
         String writeString="";
         byte[] by=new byte[(num+addzero)/8];//将变成的字节存在创建的byte数组
         System.out.println("数组的长度为"+by.length);
         int count=0;
         while(dis.available()>0){
        int i=dis.read();
        //寻找与之匹配的编码
        for(int j=0;j<list.size();j++){
        boolean bool=false;//标记是否找到
        if(list.get(j).obj==i){
        int x=0;
        while(true){
        writeString+=list.get(j).str.charAt(x)+"";
        x++;
        //如果字符串长度已经达到8位
        if(writeString.length()==8){
        byte wri=this.change(writeString);
        by[count]=wri;//将转化的字节保存到数组中
        count++;
        writeString="";//将字符串重新初始化
        }
        //如果字符串长度不足8位但是已经编码完全加入字符串中
        if(x==list.get(j).str.length()){
        bool=true;
        break;//跳出循环
            }
        }
        }
        //如果找到,则跳出循环
        if(bool==true){
        break;
        }
          }
         }
         System.out.println("此时的count为"+count);
         //如果还有剩余的字符在字符串中,则需要补0
         if(writeString.length()>0){
        int n=8-writeString.length();
        for(int i=0;i<n;i++){
        writeString+="0";
        }
        byte wri=this.change(writeString);//将8位转换为一个byte
        by[count]=wri;//写入byte数组
         }
         //此处的写入的范围为多少
//         dos.write(by.length);//写入byte数组的大小
         dos.write(by);//写入byte数组
         System.out.println("byte的数组长度为"+by.length);
        
    dis.close();//关闭输入流
    dos.close();//强制输出
    fos.close();//关闭输出流
}catch(Exception e){
e.printStackTrace();
}
   
    }
4.文件的解压
/**
* 将压缩的文件进行解压
*
*/
public void read(String path,String Newpath){
//创建存放数据的队列
ArrayList<Data> list1=new ArrayList<Data>();
try{
//创建输入流
FileInputStream fis=new FileInputStream(path);
//创建输入缓冲流
BufferedInputStream dis=new BufferedInputStream(fis);
//创建输出流
FileOutputStream fos=new FileOutputStream(Newpath);
//创建输出缓冲流
BufferedOutputStream dos=new BufferedOutputStream(fos);
/**
* 读头文件
*/
int size=dis.read();
System.out.println("队列的长度为"+size);
for(int i=0;i<size;i++){
Data data=new Data();
data.obj=dis.read();
int len=dis.read();
        byte[] by=new byte[len];
        dis.read(by);
        data.str=new String(by);
        list1.add(data);
}
int addzero=dis.read();//读出补0的情况
// int count=dis.read();//读出byte数组大小
int count=dis.available();
byte[] b=new byte[count];
System.out.println("补零数为"+addzero+"byte数组的大小为"+count);
dis.read(b);//读出byte数组
String str=new String("");
for(int i=0;i<b.length;i++){
int n=(int)b[i];
if(n<0){
n+=256;
}
str=str+this.changeInt(n);
}
//减去01字符串中末尾多加上的0
str=str.substring(0, str.length()-addzero);
boolean bool=true;
while(bool){
bool=false;
//寻找与之对应的字符
for(int i=0;i<list1.size();i++){
if(str.startsWith(list1.get(i).str)){
dos.write((int)list1.get(i).obj);
str=str.substring(list1.get(i).str.length());

bool=true;
break;
  }
}
}
//关闭输入输出流
fis.close();
dos.flush();
fos.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
看上去代码的确是很长,其中有些语句,没有深刻理解的话,确实难以弄懂。当然这个压缩也存在居多问题,比如压缩的文件大小太大,否则会卡机。可能是这个程序特别耗cpu导致的。
分享到:
评论

相关推荐

    哈夫曼压缩算法步骤,请参考具体的内容

    了解huffman算法实现的步骤及过程,并附有具体的案例以及答案了解huffman算法实现的步骤及过程,并附有具体的案例以及答案,了解huffman算法实现的步骤及过程,并附有具体的案例以及答案了解huffman算法实现的步骤及...

    C语言实现哈夫曼编码压缩和解压各种文件

    实验步骤: 1、压缩 (1) 统计原始文件中各字节出现的概率(次数); (2) 采用哈弗曼算法对各字节进行编码,建立哈弗曼对照表; a) 构造二叉树 b) 编码 (3) 依次读取原始文件的每个字节,查找其对应的哈弗曼...

    哈夫曼压缩与解压(1).txt

    哈夫曼的压缩与解压,我们老师给的代码。 构造Huffman树步骤: 根据给定的n个权值{w1,w2,……wn},构造n棵只有根结点的二叉树,令起权值为wj 在森林中选取两棵根结点权值最小的树作左右子树,构造一棵新的二叉树,...

    基于C++文件的哈夫曼编码与解码.zip

    对比二进制编码和哈夫曼编码后的文件字节大小,并计算压缩率 通过编写利用哈夫曼算法实现的文件编码解码小工具,可加深对哈夫曼算法的理解,以及编码的熟练度。本人的小工具仅针对英文大小字母及 ' '\n' ' ' 字符...

    数据结构课程设计-C++实现对于文件的哈夫曼编码与解码.zip

    数据结构课程设计-C++实现对于文件的哈夫曼编码与解码.zip编码要求及任务: 准备一个字符文件,要求: 统计该文件中各种字符的频率 ...对比二进制编码和哈夫曼编码后的文件字节大小,并计算压缩率

    基于C++实现文件的哈夫曼编码与解码【100010226】

    准备一个字符文件,要求: 统计该文件中各种字符的频率 对各字符进行 Huffman 编码,显示每个字符的编码 以及将该文件翻译成 Huffman 编码文件 ...对比二进制编码和哈夫曼编码后的文件字节大小,并计算压缩率

    哈夫曼编码实验报告(2).doc

    三、实验内容 先统计要压缩编码的文件中的字符字母出现的次数,按字符字母和空格出现的概率对 其进行哈夫曼编码,然后读入要编码的文件,编码后存入另一个文件;接着再调出编码 后的文件,并对其进行译码输出,最后...

    哈夫曼编码实验报告(3).doc

    三、实验内容 先统计要压缩编码的文件中的字符字母出现的次数,按字符字母和空格出现的概率对 其进行哈夫曼编码,然后读入要编码的文件,编码后存入另一个文件;接着再调出编码 后的文件,并对其进行译码输出,最后...

    基于C++实现哈夫曼编码解码(数据结构课程设计)【100012453】

    实现步骤可分为: 1.统计被编码文件中个字符出现的频数,即统计权重 2.根据权重,构造哈夫曼树,进行哈夫曼编码 3.读取文件进行二进制编码 4....对比二进制编码和哈夫曼编码后的文件字节大小,并计算压缩率

    链表HuffmanTree.rar

    哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树,广泛应用于数据压缩和编码领域。这个资料包提供了一种基于链表实现的哈夫曼树构建方法,相较于其他实现方式,链表结构更加紧凑,内存占用较小,且易于...

    哈夫曼函数源代码MATLAB-m4jpeg:基于JPEG的隐写工具:Mod4算法

    预编译的MEX文件(.mexwXX)执行无损压缩步骤,包括熵编码和解码。 jpeg_toolbox的zip文件包含根据多个系统预先由Matlab编译的MEX文件。 关于当前版本-M4JPEG Ver 1.4: 当前版本的M4JPEG不包含加密层,因此要隐藏的...

    基于C++、文件操作和Huffman算法实现图片压缩源码+使用说明+详细注释+sln解决方案.zip

    使用Huffman算法实现图片压缩程序,可分为6个步骤。 (1)创建工程 创建HuffmanCompressCPro工程,定义入口函数int main(); (2)读取原文件 读取文件,统计256种字节重复的次数; (3)生成Huffman树 根据上...

    基于OpenMP的文件压缩与解压的并行设计模型 (2014年)

    以动态哈夫曼算法为研究算法,将多核压缩处理并行设计模型应用到文件压缩与解压中。并在文件并行处理过程中,与数据分解法相结合对数据文件进行分割,将分解后的数据由主线程分给多个处理器上的多个子线程来并行处理...

    MATLAB图形图像处理

    17.2.2 哈夫曼( Huffman )编码 17.2.3 算术编码 17.2.4 词典编码 17.3 有损压缩编码 17.3.1 预测编码 17.3.2 正交变换编码 17.3.3 MATLAB 实现余弦变换压缩 17.3.4 MATLAB 实现小波变换压缩 附录 A 对象...

    matlab6.5图形图像处理源程序

    17.2.2 哈夫曼( Huffman )编码 17.2.3 算术编码 17.2.4 词典编码 17.3 有损压缩编码 17.3.1 预测编码 17.3.2 正交变换编码 17.3.3 MATLAB 实现余弦变换压缩 17.3.4 MATLAB 实现小波变换压缩 附录 A 对象...

    matlab6.5图形图象处理源程序

    17.2.2 哈夫曼( Huffman )编码 17.2.3 算术编码 17.2.4 词典编码 17.3 有损压缩编码 17.3.1 预测编码 17.3.2 正交变换编码 17.3.3 MATLAB 实现余弦变换压缩 17.3.4 MATLAB 实现小波变换压缩 附录 A 对象...

    VC++ matlab图像处理

    17.2.2 哈夫曼( Huffman )编码 17.2.3 算术编码 17.2.4 词典编码 17.3 有损压缩编码 17.3.1 预测编码 17.3.2 正交变换编码 17.3.3 MATLAB 实现余弦变换压缩 17.3.4 MATLAB 实现小波变换压缩 附录 A 对象...

    图形图像处理源程序-matlab6.5图形图像处理源程序.rar

    17.2.2 哈夫曼( Huffman )编码 17.2.3 算术编码 17.2.4 词典编码 17.3 有损压缩编码 17.3.1 预测编码 17.3.2 正交变换编码 17.3.3 MATLAB 实现余弦变换压缩 17.3.4 MATLAB 实现小波变换压缩 附录 ...

    数据结构习题答案(全部算法)严蔚敏版

    5.1.3 特殊矩阵的压缩存储 5.2 稀疏矩阵的三元组存储 5.2.1 三元组表 5.2.2 稀疏矩阵的运算 5.3 稀疏矩阵的十字链表存储 5.3.1 十字链表的组成 5.3.2 十字链表的有关算法 5.4 广义表 5.4.1 广义表的概念和...

Global site tag (gtag.js) - Google Analytics