`
128kj
  • 浏览: 613585 次
  • 来自: ...
社区版块
存档分类
最新评论

哈夫曼压缩与解压缩学习笔记(二)

阅读更多
继续前文"哈夫曼压缩与解压缩学习笔记(一)"
http://128kj.iteye.com/blog/1706760

(3)BitOutputStream.java
   这个类用于写压缩文件,主要方法writeBits(int[] val)用于将某一个字节的哈夫曼编码val写入文件,写的时候是一位一位先写入缓存区(写的顺序是先写缓存区的低位,后到高位),只有满八位时才flush()真正写入,如果没有八位,从下一字节中读入。

例:上面提到的文件"ASCTASCTAAAAACCTTT",共有18个字符,压缩写时先写第一个字符A,其哈夫曼编码只有一位0,先将0写入缓存区buffer的最低位,buffer=0,再写第二个字符S,一位一位的写,其哈夫曼编码为111,此时缓存区buffer=1110,然后...如下表所示:

字符写入次序    哈夫曼编码                缓冲区buffer的二进制表示
(1)A             0                 0
(2)S             111               1110
(3)C             110               0111110
(4)T             10                0  (当buffer=10111110时,清空缓存写入
                                          out,T的编码10中的1已写入,0仍在缓存中)
(5)A             0                 00
(6)S             111               11100
(7)C             110               01111100(缓存满,这是第二次写入的数据)
(8)T             10                01
(9)A             0                 001
(10)A            0                 0001
(11)A            0                 00001
(12)A            0                 000001
(13)A            0                 0000001(已有七位)
(14)C            110               01(buffer=10000001缓存满,这是第三次写入的数据)
(15)C            110               01101
(16)T            10                0101101(已有七位)
(17)T            10                0    (buffer=10101101缓存满,这是第四次写入的数据)
(18)T            10                010  最后写入的数据

这样向压缩文件写入的字节数据是: 10111110 01111100  10000001 10101101 010

import java.io.*;

public class BitOutputStream {

 private OutputStream out;
 private int buffer;//向输出流out中写一位(bit)数据时,先写入此缓存区,只有满八位时才flush()真正写入out
    private int bufferPos;//缓存区是否满的标志

    public BitOutputStream( OutputStream os )
    {
        bufferPos = 0;
        buffer = 0;
        out = os;
    }
    
    public void writeBit( int val ) throws IOException//向缓存区写一位数据val,取0或1
    {
        buffer = setBit(buffer, bufferPos++, val );//将数据写入缓存区
       if( bufferPos == BitUtils.BITS_PER_BYTES )//缓存区满时,清空并写入out文件
            flush( );
    }
    
  public void writeBits(int [] val) throws IOException//将用数组表示的哈夫曼编码val写入文件
    {
        for( int v : val )
            writeBit( v );
    }    
    
    public void flush( ) throws IOException
    {
        if( bufferPos == 0 )
            return;
        // System.out.println(Integer.toBinaryString(buffer));
        out.write( buffer );
        bufferPos = 0;//缓存区标志复位
        buffer = 0;    //缓存区清空
    }
    
    public void close( ) throws IOException//关闭文件时,要将缓存区的数据写入文件一次
    {
        flush( );
        out.close( );
    }
    
    private int setBit( int pack, int pos, int val )//将pack的第pos位的值设置为1
    {
       // System.out.println("pack="+pack+"  pos="+pos+"   val="+val);
      //  System.out.println();
        if( val == 1 )
            pack |= ( val << pos );//将pack的第pos位的值设置为1
        return pack;
    }

    public static void main(String args[]) throws IOException{
          int[] a={0,0};
          int[] b={1,1,0};
          int[] c={1,1,1};
          int[] d={1,0};
          int[] e={0,1,0,0,1};
     BitOutputStream bo=new BitOutputStream(new FileOutputStream("d:\\java\\1.txt",true));
          bo.writeBits(a);
          bo.writeBits(b);
          bo.writeBits(c);
          bo.writeBits(d);
          bo.writeBits(e);
         bo.close();
    }
    
   
}




(4)BitInputStream.java
    此类用于解压缩,主要方法readBit()从缓存区中读一位数据,缓存区低位数据先读,高位后读,当缓存区的数据读完时,再从in中读一字节放入缓存区,如何解压缩?先要从压缩文件中读出码表(字节---频率)数据,并构建哈夫曼树,然后如下进行。

例:对于先前写入压缩文件中字节数据:10111110 01111100  10000001 10101101 010,解压过程度是这样的:
(1)先读取一字节数据10111110,放入缓存buffer中,读出它的最低位数据0,然后遍历哈夫曼树,从根节点往下找左子节点,发现0正好对应节点A;

(2)再从缓存buffer中读次低位数据1,又从哈夫曼树的根节点开始找叶子节点,1就从右找,0就左找,如果没有到叶子,再从缓存buffer中读
一位数据1,还没有到叶子节点,再读一位,这样读三位111后,就找到了对应的S,

(3)再从缓存中一位一位读三次,由110从哈夫曼树中找到C

(4)这时缓存buffer中只有一位数据1可读了,读完后再从in中读一字节01111100放入缓存,这时缓存又有数据可读了,读它的最低位0,由10从哈夫曼树中找到T,再下一步找到A,S,C,T,A,A,A,A,A,C,C,T,T,T,这样可由字节数据10111110 01111100  10000001 10101101 010 还原文件"ASCTASCTAAAAACCTTT"。

import java.io.*;

public class BitInputStream {
    private InputStream in;//文件输入流
    private int buffer;//八位的缓存区,从in读入的一个字节数据先放在这里
    private int bufferPos;//缓存区标志


    public BitInputStream( InputStream is )
    {
        in = is;
        bufferPos = BitUtils.BITS_PER_BYTES;
    }
    
    //从缓存区中读一位数据,缓存区低位数据先读,高位后读,当缓存区的数据读完时,再从in中读一字节放入缓存区
    public int readBit( ) throws IOException
    {
        if ( bufferPos == BitUtils.BITS_PER_BYTES )
        {
            buffer = in.read( );//从输入流中读一个字节
           // System.out.println(Integer.toBinaryString(buffer));
            if( buffer == -1 )
                return -1;
            bufferPos = 0;
        }
       // System.out.println("buffer="+buffer);
        return getBit( buffer, bufferPos++ );    
    }
    
    public void close( ) throws IOException
    {
        in.close( );
    }
    
    private static int getBit( int pack, int pos )//获取pack的二进制表示中的第pos位上的数值.
    {
        return ( pack & ( 1 << pos ) ) != 0 ? 1 : 0;
    }
    
    public static void main(String args[]) throws IOException{
       FileInputStream is=new FileInputStream("d:\\java\\1.txt");
       BitInputStream bi=new BitInputStream(is);
       while(true){
         int b=bi.readBit();
         if(b==-1) break;
          System.out.print(b+"  ");
       }
      
   }

    
}


末完待续。。。。。。
0
0
分享到:
评论

相关推荐

    MFCHuffmanZip

    5. **压缩与解压缩流程**:在压缩过程中,原始文件先被分块,然后对每个块应用Huffman编码,生成的二进制流写入新的文件。解压缩则需要逆向执行这个过程,读取压缩文件中的二进制流,解码成原始的字符序列,最后重建...

    ACM 经验 笔记 很有用的经验指导

    - **哈夫曼树**:压缩编码,如 poj3253。 - **堆**:用于优先队列和最值问题。 - **Trie 树**:高效存储和查找字符串,分为静态建树和动态建树。 4. **简单搜索**: - **深度优先搜索(DFS)**:poj2488、poj...

    数据结构笔记的记录和心得

    其他树结构包括平衡树(如AVL树和红黑树)以及哈夫曼树(用于数据压缩)。 3. **图数据结构**:图由节点(或顶点)和连接节点的边构成,可以表示复杂的关系。图可以是无向的(边没有方向)或有向的(边有方向)。图...

    少儿编程scratch项目源代码文件案例素材-绝地求生.zip

    少儿编程scratch项目源代码文件案例素材-绝地求生.zip

    嵌入式八股文面试题库资料知识宝典-文思创新面试题2010-04-08.zip

    嵌入式八股文面试题库资料知识宝典-文思创新面试题2010-04-08.zip

    一种基于剪切波和特征信息检测的太阳斑点图融合算法.pdf

    一种基于剪切波和特征信息检测的太阳斑点图融合算法.pdf

    并联型APF有源电力滤波器Matlab Simulink仿真:dq与αβ坐标系下的谐波无功检测与PI控制及SVPWM调制

    内容概要:本文详细介绍了并联型有源电力滤波器(APF)在Matlab/Simulink环境下的仿真研究。主要内容涵盖三个关键技术点:一是dq与αβ坐标系下的谐波和无功检测,利用dq变换和FBD技术实现实时检测;二是两相旋转坐标系(dq)与两相静止坐标系(αβ)下的PI控制,通过调整比例和积分环节实现精准控制;三是SVPWM调制方式的应用,通过优化开关时序提升系统效率和性能。文中还提供了详细的仿真介绍文档,包括模型搭建、参数设定以及结果分析。 适合人群:从事电力电子、自动化控制领域的研究人员和技术人员,尤其是对电力滤波器仿真感兴趣的读者。 使用场景及目标:适用于需要深入了解并联型APF工作原理和实现方式的研究人员,旨在通过仿真工具掌握谐波和无功检测、PI控制及SVPWM调制的具体应用。 其他说明:本文不仅提供了理论知识,还结合了实际操作步骤,使读者能够通过仿真模型加深对APF的理解。

    Arduino KEY实验例程【正点原子ESP32S3】

    Arduino KEY实验例程,开发板:正点原子EPS32S3,本人主页有详细实验说明可供参考。

    嵌入式八股文面试题库资料知识宝典-嵌入式C语言面试题汇总(66页带答案).zip

    嵌入式八股文面试题库资料知识宝典-嵌入式C语言面试题汇总(66页带答案).zip

    .archivetempdebug.zip

    .archivetempdebug.zip

    嵌入式系统开发_CH551单片机_USB_HID复合设备模拟_基于CH551单片机的USB键盘鼠标复合设备模拟器项目_用于通过CH551微控制器模拟USB键盘和鼠标输入设备_实现硬.zip

    嵌入式系统开发_CH551单片机_USB_HID复合设备模拟_基于CH551单片机的USB键盘鼠标复合设备模拟器项目_用于通过CH551微控制器模拟USB键盘和鼠标输入设备_实现硬

    少儿编程scratch项目源代码文件案例素材-剑客冲刺.zip

    少儿编程scratch项目源代码文件案例素材-剑客冲刺.zip

    少儿编程scratch项目源代码文件案例素材-火影.zip

    少儿编程scratch项目源代码文件案例素材-火影.zip

    两极式单相光伏并网系统的Boost电路与桥式逆变仿真及优化方法

    内容概要:本文详细介绍了两极式单相光伏并网系统的组成及其仿真优化方法。前级采用Boost电路结合扰动观察法(P&O)进行最大功率点跟踪(MPPT),将光伏板输出电压提升至并网所需水平;后级利用全桥逆变加L型滤波以及电压外环电流内环控制,确保并网电流与电网电压同频同相,实现高效稳定的并网传输。文中还提供了具体的仿真技巧,如开关频率设置、L滤波参数计算和并网瞬间软启动等,最终实现了98.2%的系统效率和低于0.39%的总谐波失真率(THD)。 适合人群:从事光伏并网系统研究、设计和开发的技术人员,特别是对Boost电路、MPPT算法、逆变技术和双环控制系统感兴趣的工程师。 使用场景及目标:适用于希望深入了解两极式单相光伏并网系统的工作原理和技术细节的研究人员和工程师。目标是在实际项目中应用这些理论和技术,提高光伏并网系统的效率和稳定性。 其他说明:文中提供的仿真技巧和伪代码有助于读者更好地理解和实现相关算法,在实践中不断优化系统性能。同时,注意电网电压跌落时快速切换到孤岛模式的需求,确保系统的安全性和可靠性。

    昭通乡镇边界,矢量边界,shp格式

    矢量边界,行政区域边界,精确到乡镇街道,可直接导入arcgis使用

    嵌入式八股文面试题库资料知识宝典-嵌入式c面试.zip

    嵌入式八股文面试题库资料知识宝典-嵌入式c面试.zip

    嵌入式八股文面试题库资料知识宝典-I2C总线.zip

    嵌入式八股文面试题库资料知识宝典-I2C总线.zip

    岩土工程中随机裂隙网络注浆模型及其应用:不同压力下注浆效果的研究

    内容概要:本文详细介绍了三种注浆模型——随机裂隙网络注浆模型、基于两相达西定律的注浆模型、基于层流和水平集的注浆扩散模型。首先,随机裂隙网络注浆模型基于地质学原理,模拟裂隙网络发育的实际地质情况,在不同注浆压力下进行注浆作业,以增强地基稳定性和提高承载能力。其次,基于两相达西定律的注浆模型利用数学公式模拟裂隙网络中的流体输送过程,适用于裂隙网络地质条件下的注浆效果分析。最后,基于层流和水平集的注浆扩散模型通过引入层流特性和水平集方法,更准确地模拟注浆过程中的扩散过程。文中还讨论了不同注浆压力对注浆效果的影响,并提出了优化建议。 适合人群:从事岩土工程、地基加固等相关领域的工程师和技术人员。 使用场景及目标:①帮助工程师选择合适的注浆模型和注浆压力;②为实际工程项目提供理论支持和技术指导;③提升地基加固的效果和效率。 其他说明:文章强调了在实际应用中需要结合地质条件、裂隙网络特点等因素进行综合分析,以达到最佳注浆效果。同时,鼓励不断创新注浆工艺和方法,以满足日益增长的地基加固需求。

    COMSOL Multiphysics 5.5与6.0版本Ar棒板粗通道流注放电仿真的电子特性分析

    内容概要:本文详细比较了COMSOL Multiphysics软件5.5和6.0版本在模拟Ar棒板粗通道流注放电现象方面的异同。重点探讨了不同版本在处理电子密度、电子温度、电场强度以及三维视图等方面的优缺点。文中不仅介绍了各版本特有的操作方式和技术特点,还提供了具体的代码实例来展示如何进行精确的仿真设置。此外,文章还讨论了网格划分、三维数据提取和电场强度后处理等方面的技术难点及其解决方案。 适合人群:从事等离子体物理研究的专业人士,尤其是熟悉COMSOL Multiphysics软件并希望深入了解其最新特性的研究人员。 使用场景及目标:帮助用户选择合适的COMSOL版本进行高效、精确的等离子体仿真研究,特别是在处理复杂的Ar棒板粗通道流注放电现象时提供指导。 其他说明:文章强调了在实际应用中,选择COMSOL版本不仅要考虑便捷性和视觉效果,还需兼顾仿真精度和可控性。

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_8.doc.zip

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_8.doc.zip

Global site tag (gtag.js) - Google Analytics