技术开发 频道

哈夫曼树和压缩算法

  对于程序来说,取得这个编码就牵扯到一个二叉树遍历的问题了,通常来说,遍历一个二叉树可以用递归方式解决,这里举个简单的例子:

//首先,我们假设节点类为Node,包含getLChild()和getRChild()两个方法
//分别取得左子节点和右子节点,然后一个char data属性储存值
//code为储存编码的字符串,Code类为编码类,包含data和code两个个属性
public void viewBTree(Node nd,String code,List<Code> cL){
    Node leftNode
= nd.getLChild();//取得左子树
    Node rightNode = nd.getRChild();//取得右子树
    if(leftNode!=null){
        viewBTree(leftNode,code
+0”,cL);//递归,编码字符串加0
    }
    
if(rightNode!=null){
        viewBTree(rightNode,code
+1”,cL);//递归遍历右子树
    }
    
if(leftNode==null && rightNode==null){//左右子树都为空,页节点
        Code nCode = new Code(nd.data,code);//新建编码对象
        cL.add(nCode);//存入队列
    }
}

  当然也有其他方法,这里就不赘述了。

  哈夫曼树大家应该基本了解了,现在我们就需要应用它做点事了,就是今天的另一个主题:压缩算法。哈夫曼树压缩算法的原理就是对所有的byte进行重新编码,由于哈夫曼树生成的编码是长短不一的。我们可以把出现频率高的byte放在哈夫曼树的上层,出现频率低的放在下层,缩短出现频率高的byte的编码,延长出现频率低的byte的编码,替换掉固定的8位二进制编码,达到压缩的目的。所以一个所有byte完全平均的文件经过哈夫曼树压缩算法后大小不会有变化,然而这个可能性很低,通常一篇文章中总有一些字词出现频率很高,在文件中也是一样,有些byte出现频率也比较高,这种情况越不平均,哈夫曼树压缩算法的压缩效率越高。

  通过以上原理,我们就需要在对文件压缩前对文件中的所有byte做一个统计,把该byte出现的次数作为它的权,然后生成哈夫曼树,然后遍历生成编码。现在又出现一个新的问题了,我们在之前的例子中生成的编码是用字符串保存的,如何将其转换为二进制位就成了一个新的问题,因为java中最小的单位是byte,怎样把一个byte分解为单二进制位就是一个瓶颈了。当然,方法很多~~如下就是一个方法,由于java没有保存bit的单位,我们暂且用byte数组表示

/**
*将String编码转换为二进制位,用byte[]表示
*code: String 编码
*return:用byte[]表示的二进制位代码
*/
public byte[] getBit(String code){
    
byte[] bi = new byte[code.length];
    
for(int i=0;i<code.length;i++){//取出String中的每个字符
        char ch = code.charAt(i);
        
if(ch=='0'){
             bi[i]
=0;
        }
        
if(ch=='1'){
             bi[i]
=1;
        }
    }
    
return bi;
}

  然而这还不够,因为哈夫曼树组生成的编码是不等长的,而一个byte必须是8个bit组成,所以需要拼接,将不足8位的用下一个byte的编码补充完整并截断,如若a的编码是01101,b的编码是0011,那么ab组成的byte就应该是01101001 1.......,后面的则由下一位补齐。将二进制位转成二进制不算太难,如二进制位运算、二进制四则运算都可以完成。

0
相关文章