一、前言
今天了解一下压缩软件底层使用的什么算法,介绍一下常见的两种格式压缩算法,如下表,本文主要介绍DEFLATE中的哈夫曼算法
格式 | 算法 | 压缩软件 |
---|---|---|
RAR | Roshal Archive | WinRaar |
ZIP | LZ77和哈夫曼算法 | 7-Zip |
二、算法简介
压缩"hello world",根据整组数据中符号出现的频率高低,决定如何给符号编码。如果符号出现的频率越高,则给符号的码越短,相反符号的号码越长。
- 首先将这个文本中的字符提取出来,分别统计各个字符出现的频次 (h:1, e:1, l:3, o:2, w:1, r:1, d:1, 空格: 1)
- 构建哈夫曼树,每一轮都选择权重最小的两个字符相加,直至顶部只有一个节点。

- 压缩,将"hello world"用编码代替
01100111000001011110001010100110
,压缩后占32bit。压缩前按UTF-8编码,1个英文字符占1个字节,11 * 8 = 88bit,压缩率为63.64%。 - 解压,从
01100111000001011110001010100110
最左侧开始,先取出"0"去哈夫曼树中查找是否有对应的字符,如果没有就取"01"依次向后进行。
三、算法实现
javascript
// 编码器
class HuffmanNode {
constructor(char, freq) {
this.char = char;
this.freq = freq;
this.left = null;
this.right = null;
}
}
function buildHuffmanTree(charFreq) {
let nodes = charFreq.map(item => new HuffmanNode(item.char, item.freq));
while (nodes.length > 1) {
nodes = nodes.sort((a, b) => a.freq - b.freq);
const left = nodes.shift();
const right = nodes.shift();
const parent = new HuffmanNode(null, left.freq + right.freq);
parent.left = left;
parent.right = right;
nodes.push(parent);
}
return nodes[0];
}
function buildHuffmanCodes(node, currentCode, codes) {
if (node.char !== null) {
codes[node.char] = currentCode;
return;
}
if (node.left !== null) {
buildHuffmanCodes(node.left, currentCode + '0', codes);
}
if (node.right !== null) {
buildHuffmanCodes(node.right, currentCode + '1', codes);
}
}
function huffmanEncode(text) {
const charFreq = [...text].reduce((freqMap, char) => {
freqMap[char] = (freqMap[char] || 0) + 1;
return freqMap;
}, {});
const huffmanTree = buildHuffmanTree(Object.entries(charFreq));
const huffmanCodes = {};
buildHuffmanCodes(huffmanTree, '', huffmanCodes);
const encodedText = [...text].map(char => huffmanCodes[char]).join('');
return {
encodedText,
huffmanTree,
huffmanCodes,
};
}
javascript
// 解码器
function huffmanDecode(encodedText, huffmanTree) {
let decodedText = '';
let currentNode = huffmanTree;
for (const bit of encodedText) {
currentNode = bit === '0' ? currentNode.left : currentNode.right;
if (currentNode.char !== null) {
decodedText += currentNode.char;
currentNode = huffmanTree; // 重置为根节点,继续下一个编码的解码
}
}
return decodedText;
}
四、使用场景
- 做App、游戏时,本地存储数据
- 通信时压缩传输数据