我正在考虑使用霍夫曼代码来压缩文本,但使用可变长度的符号(字符串)。例如(使用下划线作为空格):
huffman-code | symbol
------------------------------------
00 | _
01 | E
100 | THE
101 | A
1100 | UP
1101 | DOWN
11100 | .
11101 |
1111...
(etc...)
如何构建频率表?显然存在一些重叠的问题,序列_TH
的出现频率与THE
几乎一样,但在表中是无用的(_
和THE
都有短的huffman码)。
这样的算法存在吗?它有一个特别的名字吗?生成频率表的技巧是什么?我需要标记输入吗?我在垃圾箱/网上什么也没找到。(所有这些都让我想起了根树)。
我在考虑使用一个迭代过程:
- 为长度为1到N的所有符号生成一个霍夫曼树
- 从树中删除所有N>1且低于特定计数阈值的符号
- 重新生成第二个huffman树,但这次用前一个来标记输入(可能使用基数树进行查找)
- 重复到1,直到我们收敛(或收敛几次)
但我不知道如何防止重叠(_TH
与THE
)的问题。
只要正确地标记文本,就不必担心重叠问题。您可以将每个标记定义为单词(最长的连续字符流)、标点符号或空白字符("、"\t"、"n")。因此,根据定义,令牌/符号不重叠。
但是直接使用霍夫曼编码并不适合压缩文本,因为它不能利用符号之间的依赖关系。例如,"q"后面可能跟有"u","qu"后面可能跟着元音,"谢谢"后面可能后跟"你"等等。你可能想研究像"LZ"这样的高阶编码器,它可以通过将数据转换为查找地址、复制长度和偏离符号的序列来利用这种冗余。下面是LZ如何工作的一个例子。然后,您可以对三个流中的每一个应用霍夫曼编码来进一步压缩数据。DEFLATE算法就是这样工作的。
这不是一个完整的解决方案。
由于您必须同时存储序列和查找表,也许您可以贪婪地选择将存储成本降至最低的符号。
步骤1:存储长度最多为k的所有符号,并跟踪它们的计数
步骤2:对于每个可能的符号,计算节省的空间(或压缩比)。
Encode_length(符号)=log(N)-log(计数(符号))
Space_saved(symbol)=长度(symbol)*计数(symbol)-编码长度(symbol
N是所有符号的总频率(我们还不知道,可能是近似值?)。
步骤3:选择最佳符号,并减去与之重叠的其他符号的频率。
步骤4:如果整个序列尚未编码,则选择下一个最佳符号(即,转到步骤2)
注意:这只是一个大纲,它既不完整,也不具有计算效率。如果你正在寻找一个实用的快速解决方案,你应该使用krjampani的解决方案。这个答案纯粹是学术性的。