如何使用诸如NEED
之类的霍夫曼代码对单词进行编码答案 0 :(得分:3)
霍夫曼编码基本上使用可变长度的位串来表示令牌(通常是具有几个例外的字符)。令牌越常见,它的位长越短,并且(通常)在处理流时是动态的。
通常有两个特殊标记,ESCAPE和END-STREAM。
编码维护一个字典,该字典基本上是用于获取令牌的位序列的查找。最初它只包含两个特殊标记。
ESCAPE和END_STREAM的初始位序列可以是0和1(这在开始时并不重要)。当编码器接收到不在字典中的字符时,它输出ESCAPE和全长令牌,然后根据所有令牌的频率将其添加并分配新的位序列。
所以你的'N'可能会产生输出流:
0 xxxxxxxx
| +- token code for N
+--- ESCAPE
和新词典:
ESCAPE:00
END-STREAM:01
N:1
然后你的'E'可能会产生输出流:
0 xxxxxxxx 0 yyyyyyyy
+- token code for E
和新词典:
ESCAPE:00
END-STREAM:01
N:10
E:11
你的下一个E不会产生ESCAPE输出,因为它已经在字典中,所以你只输出它的代码(11)。它将改变字典,因为E现在具有更高的计数。这在我们的情况下无关紧要,因为所有字符都是两个二进制数字,但是在一个更复杂的例子中,'E'标记的位长会缩短。
当D到达时,输出流变为:
0 xxxxxxxx 0 yyyyyyyy 11 0 zzzzzzzz
| +- token code for D
+------ second E
和新词典:
ESCAPE:00
END-STREAM:011
N:010
E:11
D:10
所以你可以看到,随着越来越多的角色进入,普通角色的位长减少,而不常见的角色长度增加,给你压缩。在这种情况下,N(或D)得到一个3位数的代码,而E用2位数的代码,因为它们有更多。
美妙之处在于您不需要将字典存储在文件中,因为ESCAPE部分也会动态构建它以进行解压缩。
另外,因为在结束之前永远不会有END-STREAM令牌,所以它的位长度会越来越大。类似于ESCAPE,虽然还有很多新角色进入,但它的位长仍然很短,但是当没有新角色到达时,它会遭遇与END-STREAM相同的命运。
(8位ASCII)输入流的最佳情况是只包含数百万个相同字符的文件。这对于第一个字符花费9比特,然后对于每个附加字符花费1比特,然后对于流结束花费2比特。快速接近1比8的压缩率(97.5%)。
最糟糕的情况恰好是每个字符中的一个,每个字符花费9位加上流的结尾 - 这实际上将流扩展了12.5%。
答案 1 :(得分:1)
我认为你的意思是Huffman Coding。它是一种无损地压缩数据的算法。简而言之,您将最长且最重复的连续数据位替换为最小可能的表示(这是大多数压缩的工作方式)。例如,HTML页面可能会将非常常见的<DIV
分配给二进制数01
,将每个<DIV
的32位减少到只有2位。
这是基本的想法。另一个技巧是如何选择数字,这样您就不需要使用固定大小或分隔符。这是使用Huffman Tree完成的。阅读维基百科文章了解更多信息。
答案 2 :(得分:1)
查看Huffman Coding with F#,这是一篇博客文章,介绍用F#编写的霍夫曼编码器/解码器。它简短明了。
答案 3 :(得分:0)
在C#项目中查看我的霍夫曼:https://github.com/kad0xf/HuffmanSharp