我目前正致力于在Java中实现基于霍夫曼算法的程序,而我正处于需要将编码内容输出到文件的阶段。我对如何实现解码所需的头和eof感到有点困惑。对于我的标题,我现在拥有从输入文件及其频率发生的所有唯一值,但在一些文章中我看到人们用0或1表示节点然后频率(我有点困惑)因为它没有说明符号是什么)。
另外,对于我理解的EOF,我将它编码为符号,因此它被读取和解码,但是我不知道我可以使用什么值,它肯定不会出现?我知道它需要1的权重,但不确定如何确保它实际上不在文件中。
答案 0 :(得分:3)
我必须为作业做过一次,这就是我们使用的方法。
使用0和1对树的结构(而不是频率)进行编码来完成对标头的编码。表示沿树移动的“0”,表示我们在叶节点处的“1”。这导致树的一种预先遍历遍历编码它。
例如,像(((ab)c)(de)这样的树将被编码为“0001 a
1 b
1 c
01 d
1 e
“,其中a,b,c,d,e是它们的ASCII形式。
以下是图形形式的树:
/ \
/\ /\
/\ c d e
a b
对于EOF,我们使用文件中的最后3位来指定需要读取的最后两个字节中的多少个。一旦我们读完最后一个字节(所以我们正在处理第二个最后一个字节),我们检查了最后3位:它们编码了多少读取的位数减去6.所以110101xxxxxxx000
意味着“读取110101
(6位)并丢弃其他所有内容“。 1101011xxxxxx001
表示“阅读1101011
(7位)并丢弃其余”等等。
这样做意味着我们不必具有表示EOF的特殊值,我们仍然可以一次读取一个字节(尽管我们实际上需要在我们工作的地方之前读取一个字节)。
(对于EOF,我没有看过你的文章,所以我不知道我们的想法是否适用于你的方法。)
答案 1 :(得分:2)
霍夫曼编码指定如何从某些字符序列创建霍夫曼树,然后如何将其编码为位序列。
它没有指定如何编码树或如何确切地确定要读取的位数。确切的位数是一个问题,因为您只能将整个字节保存到文件中。所以你需要一些方法来确切地知道要结束哪一位。
对于树的编码,有几个选项。其中一个是记录每个字符的计数,让解码器从中重建树。其他选项是以某种方式直接对树进行编码,例如使用0-1方法管理(我假设你提到的文章)描述。
然后有adaptive Huffman coding根本不需要树,但更复杂。
为了决定何时结束,您可以将字符总数写入文件并使用它来决定何时停止。或者,如果使用字符计数对树进行编码,则可以免费获得此计数。
另一种选择是使用EOF字符。这是您的霍夫曼树中的字符,但不编码任何正常值。假设您正在编码字节,您可以将其想象为第257个值。 (你可能使用一些正常值,如零字节,用于EOF令牌,但这需要你绝对确定它不会出现在输入文件中。)