`
杨杨和花花
  • 浏览: 22442 次
  • 性别: 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导致的。
分享到:
评论

相关推荐

    哈夫曼压缩解压算法-C语言

    mypage文件可能包含了实现哈夫曼压缩和解压缩算法的C源代码文件,以及相关的测试数据或结果。通过阅读和理解这些代码,你可以深入学习哈夫曼编码的工作原理,以及如何在C语言中实现这一算法。同时,还可以了解到如何...

    哈夫曼压缩解压缩

    总之,哈夫曼压缩解压缩是数据压缩领域的一个重要方法,通过MFC和VC++,我们可以构建出直观且高效的压缩工具,便于学习和研究。在这个过程中,理解哈夫曼编码的原理、掌握MFC的使用以及实现压缩和解压缩的算法,都是...

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

    哈夫曼编码是一种高效的数据压缩编码技术,由美国科学家大卫·哈夫曼在1952年提出。这种编码方式是基于信源符号的概率分布,通过构建最优的二叉树来实现,使得出现频率高的符号拥有较短的编码,而出现频率低的符号...

    哈夫曼压缩

    根据提供的代码片段,我们可以进一步理解哈夫曼压缩的具体实现步骤: 1. **数据结构定义**: - `struct head` 定义了哈夫曼树中节点的数据结构,包括节点对应的字符(`b`)、出现频率(`count`)、父节点索引(`parent`...

    java实现哈夫曼压缩的实例

    在Java中实现哈夫曼压缩涉及到的主要步骤包括统计字节频率、构建哈夫曼树以及生成哈夫曼编码。首先,我们需要创建一个字节类(`NodeData`)来表示每个字节及其对应的权重(频率)。下面我们将详细讲解这些步骤: 1....

    哈夫曼压缩与解压文件课程设计(代码+实习报告)

    哈夫曼编码是一种高效的数据压缩方法,由大卫·哈夫曼在1952年提出。它是基于一种称为哈夫曼树(也叫最优二叉树)的数据结构。在这个课程设计中,你将深入理解哈夫曼编码的原理,并通过C++编程语言实现文件的压缩与...

    huff.rar_MATLAB 图片压缩_huff_哈夫曼 压缩_哈夫曼压缩_图片压缩matlab

    在MATLAB中,哈弗曼编码通常包括以下几个步骤: 1. **频率统计**:首先,我们需要计算输入图片(如`lena.jpg`)中每个像素颜色值出现的频率。MATLAB中可以使用`imhist`函数来获取像素的直方图,这将帮助我们了解...

    哈夫曼压缩与解压缩程序(JAVA)

    在Java编程环境中实现哈夫曼压缩与解压缩程序,我们可以利用面向对象的特性,设计多个类来完成不同部分的功能。 1. **FileChooserDemo.java**:这是一个用户界面类,通常包含用于让用户选择输入和输出文件的控件。...

    哈夫曼压缩.zip

    在"哈夫曼压缩.zip"这个压缩包中,我们可以预见到包含了一个与哈夫曼压缩相关的项目。这个项目可能是用Visual Studio(VS)开发环境编写的,这意味着它可能是一个C++、C#或Visual Basic等编程语言的实现。实习性质...

    哈夫曼压缩和解压c++(源码)

    在C++中实现哈夫曼压缩和解压,主要涉及到数据结构(如优先队列、二叉树)和文件操作(读写)。`huffmain`可能是这个C++项目的主程序文件,其中可能包含了构建哈夫曼树、生成编码、压缩和解压等核心功能的实现。具体...

    java哈夫曼压缩

    在Java中实现哈夫曼压缩通常包括以下几个关键步骤: 1. **构建哈夫曼树**:首先,需要统计输入文本中每个字符出现的频率。然后,根据这些频率创建一个哈夫曼树。哈夫曼树是一种特殊的二叉树,其特点是叶子节点代表...

    java 哈夫曼压缩算法的分析与实现[源码][附图]

    在Java中实现哈夫曼压缩涉及到以下几个关键步骤: 1. **统计字符频率**:首先,需要遍历输入文本,统计每个字符出现的次数,生成一个字符频率表。这是构建哈夫曼树的基础。 2. **构建哈夫曼树**:使用字符频率表,...

    哈夫曼树压缩算法实现

    在实现哈夫曼树压缩算法的过程中,通常包括以下几个步骤: 1. **频率统计**:首先,对输入的数据流进行频率统计,得到每个符号(如字符)出现的次数。这一步骤有助于了解哪些符号更常见,哪些更不常见。 2. **构建...

    huffman压缩速度优化算法

    优化的哈夫曼压缩步骤如下: 1. **频率统计**:首先,对输入数据流中的每个字符进行频率统计,得到每个字符出现的次数。 2. **构建哈夫曼树**:使用频率统计结果,通过贪心算法构建哈夫曼树。树的每个内部节点表示...

    哈夫曼编码实现压缩解压缩java

    - 重复此步骤,每次选择频率最小的两个节点合并,直到只剩下一个节点,即为哈夫曼树的根节点。 3. **哈夫曼编码生成**: - 对哈夫曼树进行遍历,从根节点到叶节点的路径确定了字符的编码。左分支代表0,右分支...

    哈夫曼压缩算法(源代码+实现报告)

    1. **算法介绍**:详细解释哈夫曼压缩的基本原理和步骤。 2. **设计思路**:描述代码实现的具体策略和考虑,如如何优化效率,处理边界情况等。 3. **实现细节**:列出关键函数的实现,可能包括频率统计函数、哈夫曼...

    哈夫曼编码压缩解压.rar

    在Java中实现哈夫曼编码压缩和解压,你需要以下几个关键步骤: 1. **编码阶段**: - 实现哈夫曼树的构建算法,如上述描述。 - 为每个字符生成哈夫曼编码,并存储在一个映射表中,以便后续解码使用。 - 遍历原始...

    哈夫曼树 压缩.pdf

    本文将详细介绍哈夫曼编码的基本原理、实现步骤以及如何将其应用于文本文件的压缩。 #### 二、哈夫曼编码算法 ##### 1. 基本原理 哈夫曼编码是一种基于统计的无损数据压缩算法,它通过构建哈夫曼树来实现对字符的...

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

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

    利用哈夫曼原理的压缩解压缩软件

    压缩过程主要包括以下步骤: 1. **统计频率**:首先,程序读取待压缩文件(如txt和doc文件),统计每个字符或字节的出现频率。 2. **构建哈夫曼树**:根据频率构建哈夫曼树,频率高的字符对应较短的编码,频率低的...

Global site tag (gtag.js) - Google Analytics