赞
踩
说到哈夫曼编码,我们先了解一下什么是哈夫曼树:
哈夫曼树(Huffman Tree)是在叶子结点和权重确定的情况下,带权路径长度最小的二叉树,也被称为最优二叉树。
故依据哈夫曼树的带权路径长度最小的这个特点,我们可以实现对文件进行压缩。
一般情况下我们考虑对文本文件进行压缩,而很少考虑对图片、音频等进行压缩,对于此的原因这里我总结了几点如下:
下面我们以一段代码来统计一下一个视频文件中各个字节出现的频次
- public class Demo {
- public static void main(String[] args) throws IOException {
- FileInputStream fis=new FileInputStream("C:\\Users\\zyx\\Desktop\\4.mp4");
- FileOutputStream fos=new FileOutputStream("C:\\Users\\zyx\\Desktop\\1.mp4");
- int len;
- byte[] buf=new byte[1024];
- HashMap<Byte,Integer> map=new HashMap<>();
- while((len=fis.read(buf))!=-1) {
- for(int i=0;i<len;i++) {
- if(map.get(buf[i])==null) {
- map.put(buf[i], 1);
- }else {
- map.put( buf[i], map.get(buf[i])+1);
- }
- }
- }
- System.out.println(map);
- }
- }
运行结果如下:
可以明显的看到除了0以外的各个字节出现的频次都非常接近,故猜测我们在对这类文件进行编码压缩时,最终结果在很大概率上压缩效率会很低,甚至还可能发生膨胀的情况,这与我们期望的压缩的目的就背道而驰了。
了解了选择.txt文本文件的原因后,我们再来了解一下哈夫曼树的建树过程:
补充:可以发现在实际的压缩过程中,建树环节是最消耗时间的一块,因此对于上面的2过程,推荐使用快速排序的方式,这样相比于普通的冒泡排序的方式,效率的提升就非常明显了
看一下冒泡和快排部分的代码:
- public void sort() {
- Node dem;
- for(int i=0;i<nodes.size()-1;i++) {
- for(int j=0;j<nodes.size()-1-i;j++) {
- if(nodes.get(j).weight>nodes.get(j+1).weight) {
- dem=nodes.get(j);
- nodes.set(j, nodes.get(j+1));
- nodes.set(j+1, dem);
- }
- }
- }
- }
- public void quickSort(int begin,int end) {
- if(begin<end) {
- Node temp=nodes.get(begin);
- int i=begin;
- int j=end;
- while(i<j) {
- while(i<j&&nodes.get(j).weight>temp.weight)
- j--;
- nodes.set(i, nodes.get(j));
- while(i<j&&nodes.get(i).weight<=temp.weight)
- i++;
- nodes.set(j, nodes.get(i));
- }
- nodes.set(i, temp);
- quickSort(begin, i-1);
- quickSort(i+1, end);
- }
- }
上面的是普通冒泡排序的代码,下面的是快速排序的代码
下面通过程序运行来测试两种排序在压缩一个413KB的文本文件的耗时,运行结果如下:
冒泡的运行结果:
快排的运行结果:
由运行结果可见,由冒泡排序改为快排后效率的提升约8倍有余
在看完前言后,下面进入正式部分
一、实现思路
1、压缩:
2、解压
针对效率问题的一个补充:在使用文件流读取压缩文件时,事先声明了一个长度为1024,元素类型为byte的数组,使用read(byte b[])方法,每次都读取最多1024字节的数据到字节数组,好处是减少了与操作系统交互的次数,提高了读取的效率,同时该数组的长度若过大则内容占用也会较大也会影响效率,因此数组的长度适中即可
3、编码器界面
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。