霍夫曼编码的实现步骤
统计字符频率
首先,需要统计待压缩数据中每个字符出现的频率。假设我们有一个字符串 "ABRACADABRA",我们可以统计每个字符的频率如下:
A: 5 B: 2 R: 2 C: 1 D: 1
构建霍夫曼树
根据字符频率,我们可以构建一棵霍夫曼树。霍夫曼树是一种特殊的二叉树,其中字符频率较低的字符在树的顶部,而频率较高的字符在树的底部。
首先,将所有字符作为独立的树节点,并按照字符频率进行排序。然后,将频率最低的两个节点合并为一个新节点,频率等于这两个节点的频率之和。重复这个过程,每次合并产生一个新的节点,直到只剩下一个节点为止。这个节点就是霍夫曼树的根节点。
下图展示了通过合并节点逐步构建的霍夫曼树的过程:
生成霍夫曼编码
根据霍夫曼树,可以为每个字符生成对应的霍夫曼编码。霍夫曼编码是一种前缀编码,即没有一个编码是另一个编码的前缀。在霍夫曼树中,从根节点到每个叶子节点的路径上的左分支用0表示,右分支用1表示。
通过从根节点出发,沿着路径到达目标字符所在的叶子节点,并记录经过的分支方向(0或1),即可生成该字符的霍夫曼编码。
下图展示了根据霍夫曼树生成霍夫曼编码的过程:
压缩数据
最后,使用生成的霍夫曼编码将原始数据进行压缩。将原始数据中的每个字符替换为其对应的霍夫曼编码,即可得到压缩后的数据。
例如,将字符串 "ABRACADABRA" 使用上述的霍夫曼编码进行压缩,结果为:"0101110110110010111110"。
通过以上步骤,我们成功地对数据进行了霍夫曼编码压缩。在解压时,只需使用相同的霍夫曼树和编码表,将压缩的数据逆向解码即可恢复原始数据。
实战:统计英文文章各字符出现的次数
选取一段不少于3000字的英文材料,统计各字符出现的次数,实现Huffman编码,以及对编码结果的解码,代码:
% 读取文本文件
fid = fopen('Huffman.txt', 'r');
text = fscanf(fid, '%c');
fclose(fid);
% 将字符转换为ASCII值
text_ascii = double(text);
% 统计字符频率
symbols = unique(text_ascii);
[counts, ~] = histcounts(text_ascii, [symbols, max(symbols)+1]);
prob = counts / sum(counts);
% 创建Huffman字典
dict = huffmandict(symbols, prob);
% Huffman编码
comp = huffmanenco(text_ascii, dict);
% 将编码结果保存到文件中
fid = fopen('code.dat', 'w');
fwrite(fid, comp);
fclose(fid);
% 解码
decomp = huffmandeco(comp, dict);
% 检查解码是否正确
isequal(text_ascii, decomp)
% 输出每个字符出现的次数和编码,并存储到文件中
fid = fopen('Huffman.txt', 'w');
for i = 1:length(dict)
fprintf(fid, '%s: %d times, code: %s\n', char(dict{i,1}), counts(i), num2str(dict{i,2}));
end
fclose(fid);