哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。
哈夫曼编码,主要目的是根据使用频率来最大化节省字符(编码)的存储空间。
本文主要利用霍夫曼编码来压缩字节数组(可以是任何文件),同时修复了尚硅谷韩顺平老师的bug,对于字节数组最后一位的补位问题
流程主要是
1.源字节数组—>根据各个字节出现的频次,创建有权重(即该字节出现的次数)的二叉树结点,存储到列表中
2.根据上一步的列表list,创建霍夫曼树(创建过程原理可参照百度,原理较为简单),获得根节点
3.获得霍夫曼树后,重新编码,根据路径左0右1的原则,对每个字符的霍夫曼编码存储到map中,便于后续压缩
4.对照编码map,对源字节数组重新编码,获得一串二进制数组
5.编码后的二进制数组,每8位存储为一个字节,得到的结果就是编码压缩后的新字节数组。
6.解码:先将压缩后的字节数组依次读取转成二进制字符串
7.反转map,依次读取二进制字符串,还原源字节数组
附上源码
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HuffmanCode {
public static void main(String[] args) {
zipFile("G:/src.bmp", "G:/dest.zip");
System.out.println("压缩成功");
unZipFile("G:/dest.zip", "G:/src2.bmp");
System.out.println("解压成功");
/*
String content = "i like like like java do you like a javae";
// String content = "你好";
byte[] contentBytes = content.getBytes();
System.out.println("原文件字节数组:"+Arrays.toString(contentBytes));
// System.out.println("原文件字节数组长度="+contentBytes.length);//40
byte[] huffmanCodeBytes = huffmanZip(contentBytes);
System.out.println("压缩后的数组为:"+Arrays.toString(huffmanCodeBytes));
byte[] decodeBytes = decode(huffmanCodes, huffmanCodeBytes);
System.out.println("解码后的结果:"+new String(decodeBytes));
*/
/*
List<Node> nodes = getNodes(contentBytes);
System.out.println(nodes);
Node huffmanTreeRoot = createHuffmanTree(nodes);
huffmanTreeRoot.preList();
Map<Byte, String> huffmanCodes = createHuffmanCode(huffmanTreeRoot);
System.out.println(huffmanCodes);
byte[] huffmanCodeBytes = zip(contentBytes, huffmanCodes);
System.out.println(Arrays.toString(huffmanCodeBytes)); //只有17长度*/
}
//存放哈夫曼编码表
static Map<Byte, String> huffmanCodes = new HashMap<>();
//二进制字符串8位存放一个字节,存放编码后的最后一个数字位数
static int lastNumCap;
//解压文件
public static void unZipFile(String src,String dest) {
InputStream is = null;
ObjectInputStream ois = null;
OutputStream os = null;
try {
is = new FileInputStream(src);
ois = new ObjectInputStream(is);
byte[] srcBytes = (byte[]) ois.readObject();//读取的编码后的字节数组
Map<Byte, String> huffmanCodes = (Map<Byte, String>) ois.readObject();//读取编码表
byte[] destBytes = decode(huffmanCodes, srcBytes);
os = new FileOutputStream(dest);
os.write(destBytes);
os.flush();
} catch (Exception e) {
System.out.println(e.getMessage());
}finally {
try {
os.close();
ois.close();
is.close();
} catch (IOException e)