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

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

阅读更多
继续前文"哈夫曼压缩与解压缩学习笔记(二)"http://128kj.iteye.com/blog/1706818
    下面两个类主要是根据字节计数器的统计结果,创建哈夫曼树,计算字节的哈夫曼编码及由哈夫曼编码在树中找节点,往文件中写码表,读码表.
(5)HuffNode.java
//哈夫曼树节点

public class HuffNode  implements Comparable<HuffNode>
{
    public int value;//节点的字节值
    public int weight;//节点的权值(字节出现的频率)
    
    public int compareTo( HuffNode rhs )
    {
        return weight - rhs.weight;
    }
    
    HuffNode left;//左节点
    HuffNode right;//右节点
    HuffNode parent;//父节点
    
    HuffNode( int v, int w, HuffNode lt, HuffNode rt, HuffNode pt )
    {
        value = v; weight = w; left = lt; right = rt; parent = pt;
    }
}


(6)HuffmanTree.java

//哈夫曼树

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.PriorityQueue;
import java.io.*;
public class HuffmanTree {

    
    public long charCountSum;
    private CharCounter theCounts;//字节计数器
    //存放哈夫曼树的所有节点,字节i对应的节点是theOndes[i]
    private HuffNode [ ] theNodes = new HuffNode[ BitUtils.DIFF_BYTES + 1 ];//256+1
    private HuffNode root;//哈夫曼树的根节点

    public HuffmanTree( )
    {
        theCounts = new CharCounter( );
        root = null;
    }
    
    public HuffmanTree( CharCounter cc )//构造函数
    {
        theCounts = cc;//注入字节计数器
        root = null;
        createTree( );//创建哈夫曼树
        charCountSum=charCountSum();//总的字节数(原文件的大小)
    }
    
    public static final int ERROR = -3;
    public static final int INCOMPLETE_CODE = -2;
    public static final int END = BitUtils.DIFF_BYTES;
    
              
    //根据字节计数器的统计结果,创建哈夫曼树,
    private void createTree( )
    {
        PriorityQueue<HuffNode> pq = new PriorityQueue<HuffNode>( );//优先队列
        
  for( int i = 0; i < BitUtils.DIFF_BYTES; i++ )//对0---256之间的每一个字节构造哈夫曼节点
            if ( theCounts.getCount( i ) > 0 )
            {
                //以字节值,字节在原文件中出现的次数(权)构建哈夫曼节点
                HuffNode newNode = new HuffNode( i,
                       theCounts.getCount( i ), null, null, null );
                theNodes[ i ] = newNode;//保存节点
                pq.add( newNode );//节点加入优先队列
            }
              
        while( pq.size( ) > 1 )//创建哈夫曼树
        {
            HuffNode n1 = pq.remove( );
            HuffNode n2 = pq.remove( );
            HuffNode result = new HuffNode( INCOMPLETE_CODE,
                                  n1.weight + n2.weight, n1, n2, null );
            n1.parent = n2.parent = result;
            pq.add( result );
        }      
        
        root = pq.element( );//返回哈夫曼树的根
    }

  
    public int[] getCode( int ch )//以整型数组的形式返回字节ch的哈夫曼编码,如{1,1,0},{1,1,1}
    {
        HuffNode current = theNodes[ ch ];//找到与ch对应的节点
        if( current == null )
            return null;
            
        String v = "";
        HuffNode par = current.parent;//ch的直接父节点
        
        while ( par != null )//找ch的父节点,一直到根
        {
            if( par.left == current )//顺带写出ch的哈夫曼码
                v = "0" + v;
            else
                v = "1" + v;
            current = current.parent;
            par = current.parent;
        }
      
        int [ ] result = new int[ v.length( ) ];
        for( int i = 0; i < result.length; i++ )
            result[ i ] = v.charAt( i ) == '0' ? 0 : 1;
            
        return result;//以整型数组的形式返回字节ch的哈夫曼编码
    } 
    
    
    public int getChar( String code )//由字节的哈夫曼编码求出此字节
    {
        HuffNode p = root;
        for( int i = 0; p != null && i < code.length( ); i++ )
            if( code.charAt( i ) == '0' )
                p = p.left;
            else
                p = p.right;
                
        if( p == null )
            return ERROR;
            
        return p.value;            
    }

    //解压缩的关键方法
//从BitInputStream流中一位一位的读(然后在树中找节点),直到读到一个哈夫曼编码,返回哈夫曼编码对应的字节值
    public int getChar(BitInputStream bips) throws IOException
    {
    	HuffNode p = root;//哈夫曼树的根节点
    	while( p!=null)
    	{	
	    	int bit=bips.readBit();//从流中读一位
	    	if(bit==-1)
	    		return -1;
	        if(bit == 0 )//如果是0,在哈夫曼树中向左找
	        	p =p.left;
	        else
	        	p =p.right;//如果是1,在哈夫曼树中向右找
	        if(p.left==null&&p.right==null)
	        	break;
    	}   
       
        if( p == null )
            return ERROR;
    	return p.value;
    }
    
     //往压缩文件中写编码表信息:字节----字节的权值(出现的次数)
    public void writeEncodingTable( DataOutputStream out ) throws IOException
    {
    	
        for( int i = 0; i < BitUtils.DIFF_BYTES; i++ )
        {
            if( theCounts.getCount( i ) > 0 )
            {
                out.writeByte( i );//写字节
                out.writeInt( theCounts.getCount( i ) );//写字节出现的次数
            }
        }
        out.writeByte( 0 );
        out.writeInt( 0 );//写一个结束标志
        
    }
    
   //读哈夫曼编码表
    public void readEncodingTable( DataInputStream in ) throws IOException
    {
        for( int i = 0; i < BitUtils.DIFF_BYTES; i++ )
            theCounts.setCount( i, 0 );//初值全部为0
        
        int ch;
        int num;
        
        for( ; ; )
        {
            ch = in.readByte( );//读字节值
            num = in.readInt( );//字节的权值
            if( num == 0 )//遇到结束标志
                break;
            theCounts.setCount( ch, num );//将读到的结果放入字节计数器
        }
        
        createTree( );//根据字节计数器中的数据,创建哈夫曼树
        charCountSum=charCountSum();//原文件总的字节数
    }
   
    public long charCountSum()//计算原文件总的字节数
    {
    	return theCounts.charCountSum();
    	
    }

}
  



最后一个类,完成压缩和解压缩操作
import java.io.*;
import java.util.Calendar;

public class Hzip {

   //压缩文件
 public static void compress( String inFile ) throws IOException {
   //读取数据文件
		
   FileInputStream fis =new FileInputStream(inFile);//要压缩的文件
   CharCounter charCounter=new CharCounter(fis);//字节计数器,统计文件中字节出现的次数
HuffmanTree tree=new HuffmanTree(charCounter);//根据字节计数器统计的结果创建哈夫曼树,得到根节点
	
   fis.close();
	    
	
   String compressedFile = inFile + ".huf";//压缩文件的扩展名为huf       
   OutputStream fout =null;
   fout=new FileOutputStream( compressedFile );//准备要写的压缩文件
        
  DataOutputStream out=new DataOutputStream(fout);
 tree.writeEncodingTable(out);//往压缩文件中写入码表(字节--出现次数)信息,以便解压缩时恢复哈夫曼树
		
  fis=new FileInputStream(inFile);//原文件
  BitOutputStream hzout = new BitOutputStream(fout );//压缩后的文件

  int ch;
  while( ( ch = fis.read( ) ) != -1 )//从原文件中读一个一个字节地读
  {
  hzout.writeBits( tree.getCode(ch) );//写入这个字节到压缩文件,八位八位地写
  }    
    fis.close( );
     
    hzout.close( );  
    fout.close();
  }
        //解压缩文件
 public static void uncompress( String compressedFile ) throws IOException{
        String outFile;
        String extension;
        
        outFile = compressedFile.substring( 0, compressedFile.length( ) - 4 );
        extension = compressedFile.substring( compressedFile.length( ) - 4 );
        
        if( !extension.equals( ".huf" ) )//先判断要解压文件的扩展名
        {
            System.out.println( "Not a compressed file!" );
            return;
        }
        
       
        InputStream fin = new FileInputStream(compressedFile );//准备读
        DataInputStream in = new DataInputStream( fin );
          
        HuffmanTree tree=new HuffmanTree();

   //先从已压缩文件中读出码表(字节---字节出现的次数)信息,并由此信息创建哈夫曼树,
        //具体代码请参看tree.readEncodingTable(in)方法
        tree.readEncodingTable(in);

        System.out.println("总频数:"+tree.charCountSum);
        //解码,开始解码压缩文件
        BitInputStream hzin = new BitInputStream( in );
        
      OutputStream fout = new FileOutputStream( outFile );//准备输出文件
        int ch;
        long count=0;

         
//tree.getChar(hzin)方法从BitInputStream流中一位一位的读(然后在树中找节点),
        //直到读到一个哈夫曼编码,返回此哈夫曼编码对应的字节值
        while(( ch =tree.getChar(hzin) ) != -1 )
        {
        	fout.write(ch );//将解压后的字节写入输出文件
       		count++;
    		if(count>=tree.charCountSum)
    			break;
        }
        fin.close();
        hzin.close( );
        fout.close( );
    }
    
    //大家测试吧
    public static void main( String [ ] args ) throws IOException
    {
    	String cf="D:\\temp\\7.bmp";
    	long start = System.currentTimeMillis();
    	//compress(cf);
    	uncompress(cf+".huf");
    	long end = System.currentTimeMillis();
    	System.out.println("耗时: " + (end-start)+ " 毫秒"); 
    }
    public static void main2( String [ ] args ) throws IOException
    {
        if( args.length < 2 )
        {
            System.out.println( "Usage: java Hzip -[cu] files" );
            return;
        }
        
        String option = args[ 0 ];
        for( int i = 1; i < args.length; i++ )
        {
            String nextFile = args[ i ];
            if( option.equals( "-c" ) )
                compress( nextFile );
            else if( option.equals( "-u" ) )
                uncompress( nextFile );
            else
            {
                System.out.println( "Usage: java Hzip -[cu] files" );
                return;
            }
        }
    }
}

全文完。下载源码:
2
2
分享到:
评论

相关推荐

    哈夫曼压缩与解压缩源码.zip

    哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩...

    哈夫曼压缩与解压缩

    哈夫曼实现文件的压缩与解压缩,代码关键部分有注释。

    哈夫曼压缩解压缩

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

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

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

    哈夫曼压缩与解压缩设计

    为了解压缩时重建哈夫曼树,压缩文件需要保存编码信息,包括ASCII值和对应的位序列。 解压缩阶段相对简单,从输入缓冲区中读取已编码的位流,然后遍历位流,根据哈夫曼树的结构寻找对应的叶节点,即字符的ASC II码...

    哈夫曼解压缩程序

    哈夫曼解压缩程序,通常被称为Szip,是一种基于哈夫曼编码的高效数据压缩算法。在信息技术领域,数据压缩是存储和传输信息的关键技术,它通过减少数据冗余来节省存储空间和提高传输效率。哈夫曼编码是数据压缩中的...

    哈夫曼编码压缩解压缩程序(CPP写的)

    哈夫曼编码是一种高效的数据压缩方法,它基于字符出现频率构建最优的二叉树结构,从而实现数据的压缩与解压缩。本文将深入探讨哈夫曼编码的原理,并通过一个使用C++编写的哈夫曼编码压缩解压缩程序,来阐述其具体...

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

    5. **解压缩**:在解压缩阶段,从二进制序列开始,按照哈夫曼树的结构进行反向操作。每当遇到0时,向左移动;遇到1时,向右移动。当到达叶子节点时,读取该节点的字符,并输出。然后返回到根节点,继续解码剩余的二...

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

    哈夫曼编码是一种高效的数据编码方法...在Java中,我们可以使用面向对象的方式设计数据结构和算法,结合文件操作类实现文件的压缩与解压缩。通过这个过程,我们可以有效地减小文本文件的存储空间,提高存储和传输效率。

    哈夫曼实现压缩解压缩——源代码

    哈夫曼编码是一种高效的数据压缩方法,由大卫·哈夫曼在1952年提出。它是基于频率的变字长编码...通过阅读和分析提供的源代码,你可以更直观地了解哈夫曼编码的工作原理,并可能从中学习到如何优化和改进数据压缩算法。

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

    在“利用哈夫曼原理的压缩解压缩软件”中,哈夫曼编码被应用于文件的压缩与解压缩过程。 MFC(Microsoft Foundation Classes)是微软开发的一种C++库,用于构建Windows应用程序。它提供了丰富的类结构,使得开发者...

    这是哈夫曼压缩与解压缩的全套代码和需要的txt文件

    这是哈夫曼压缩与解压缩的全套代码和需要的txt文件,huffman,tree

    基于哈夫曼编码的文本文件压缩与解压缩

    哈夫曼编码是一种高效的数据编码方法,主要用于无损数据压缩。在信息技术领域,尤其是...通过C语言实现哈夫曼编码的压缩与解压缩,有助于理解数据压缩的基本原理,并为进一步学习和开发更高级的压缩算法奠定基础。

    C语言实现的基于Huffman哈夫曼编码的数据压缩与解压缩.7z

    在C语言中实现哈夫曼编码的压缩与解压缩,涉及到的主要知识点包括以下几个方面: 1. **哈夫曼树的构建**:哈夫曼树是一种带权路径长度最短的二叉树。构建过程通常采用贪心策略,通过合并频率最小的两个节点来逐步...

    哈夫曼压缩解压缩的代码

    - 解压缩的过程与压缩相反。首先需要重建哈夫曼树,然后按照编码流逐位解析,根据哈夫曼树的结构确定每个编码对应的字符,从而还原出原始数据。 5. **Java实现** - 在Java中,可以使用`PriorityQueue`来实现最小...

    基于哈夫曼编码的文本文件压缩与解压缩.zip

    在“基于哈夫曼编码的文本文件压缩与解压缩.zip”这个压缩包中,很可能包含了用于演示或教学目的的哈夫曼编码实现代码、压缩和解压缩的示例文本以及相应的结果文件。学习和理解这个压缩包的内容,可以帮助我们更好地...

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

    在这个课程设计中,你将深入理解哈夫曼编码的原理,并通过C++编程语言实现文件的压缩与解压功能。 哈夫曼编码的核心思想是根据字符出现的频率来构建一个特殊的二叉树。在这个树中,频率较高的字符会被放在较近的叶...

    vc++哈夫曼压缩算法

    vc++哈夫曼压缩算法 vc++哈夫曼压缩算法

    基于哈夫曼树的文件压缩与解压缩.rar

    在本项目“基于哈夫曼树的文件压缩与解压缩”中,开发者利用Python实现了对doc和txt文件的压缩与解压缩功能,确保了原始文件在解压后能完全恢复,不造成任何信息失真。 哈夫曼编码的基本原理是通过构建一个特殊的...

    java哈夫曼压缩和解压

    Java哈夫曼编码是一种数据压缩技术,它基于哈夫曼树进行编码,通过构建最优的二叉树结构来实现高效的数据编码与解码。在Java中实现哈夫曼压缩和解压涉及到以下几个关键知识点: 1. **哈夫曼树**: 哈夫曼树...

Global site tag (gtag.js) - Google Analytics