解码HTTP / 2中的霍夫曼编码

时间:2018-01-13 17:08:13

标签: huffman-code

我试图了解如何对HTTP / 2标头进行霍夫曼解码。我看到的大多数文档都谈到了频率表的二叉树,但对于HTTP / 2,它只是一个静态查找表。我的编码部分工作正常,但解码让我感到困惑,因为我不知道如何判断我每次应该占多少比特。

1 个答案:

答案 0 :(得分:2)

霍夫曼代码是prefix-free code。这意味着没有编码符号是任何其他编码符号的前缀。

如果有一个由位字符串00111表示的符号,则不能由0011100011110011100110011表示的符号 - 没有别的将以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子节点。)

由于您有静态代码列表,因此您只需构建一次树,并且可以在程序的生命周期内重复使用它。