我试图了解如何对HTTP / 2标头进行霍夫曼解码。我看到的大多数文档都谈到了频率表的二叉树,但对于HTTP / 2,它只是一个静态查找表。我的编码部分工作正常,但解码让我感到困惑,因为我不知道如何判断我每次应该占多少比特。
答案 0 :(得分:2)
霍夫曼代码是prefix-free code。这意味着没有编码符号是任何其他编码符号的前缀。
如果有一个由位字符串00111
表示的符号,则不能由001110
或001111
或0011100110011
表示的符号 - 没有别的将以00111
开头。如果您已阅读位字符串00111
,则不需要标记来告诉您,您已经在符号的末尾。如果可以从您到目前为止读取的位中生成输出符号,则必须生成该输出符号并开始读取下一个符号。
当您阅读0011
时,由于0011
不是符号,您无法输出任何内容。它不可能,因为它是00111
的前缀。
霍夫曼代码总是为每个可能的位串赋予一些含义(除了过早结束的位)。 0011
本身没有意义的事实意味着必须至少有2个以0011
开头的符号代码。至少有一个会以00110
开头,至少一个会以00111
开头。
要解码输入比特流,您从表示无输入的状态开始,然后读取一个比特,然后移动到表示您目前读取的比特的状态。例如,如果您处于状态00
并且读取1,则转到状态001
。当您达到与符号对应的状态时,输出该符号并在读取下一位之前返回初始状态。
(请注意,检测流的结尾超出了霍夫曼编码的范围。包含的协议必须告诉您如何知道何时在比特流的末尾。)
由于每个状态恰好有2个可能的后继状态(对应于0
位和1
位),因此状态转换形成二叉树。在每个非叶子节点,你要读一点来决定是去左边的孩子还是右边的孩子,并且在你完成解码符号的每个叶子节点上输出那个符号,然后回到根。
您可以从符号列表及其编码构建树,然后遍历树以解码输入。编写构建树的代码可能会为您提供真正理解霍夫曼代码的体验。
当你有一个像
这样的输入列表时A 00
B 010
C 011
D 100
E 1010
F 1011
G 1100
H 1101
I 1110
J 1111
你的树结构应该满足
root->symbol is null
root->left->symbol is null
root->left->left->symbol = A
root->left->right->left->symbol = B
root->left->right->right->symbol = C
...
(在这个伪代码中,每个节点都有3个属性,但在实际语言中,您可能会找到更有效的表示。每个节点都需要symbol
或一对指针/引用{ {1}}和left
子节点。)
由于您有静态代码列表,因此您只需构建一次树,并且可以在程序的生命周期内重复使用它。