我正在阅读霍夫曼编码算法来编码字符串。我可以看到字符的频率被考虑在一起构成一棵树。
以下是频率表:
a b d e f h i k n o r s t u v
5 1 3 7 3 1 1 1 4 1 5 1 2 1 1 9
*space has frequency 9
我可以看到有一棵树。但我无法推导出如何在树中放置元素的规则。
这本书说所有频率较高的角色应该靠近根。但如果两个以上的字符具有相同的频率,那么它们必须位于根的不同侧。
问题是,我们如何决定立场?
在我的书a
中有代码010
,r
有011
而e
有代码100
。
有人可以帮忙吗?
答案 0 :(得分:3)
你试过Wikipedia吗?有一个关于霍夫曼编码的很好的演示。算法很简单:你需要一个priority queue。
算法有点像这样:
1. Create tree nodes with each character and their frequencies
2. Put all the letters and their frequencies in a priority queue Q
3. Do until Q contains only one element:
3a. Pick two lowest-frequency items a, b
3b. Create a tree node z with frequency(z) = frequency(a) + frequency(b)
3c. Add a and b as left and right children of z
3d. Put z in Q
4. Pick up the only element from Q. This would be the root of the tree.
5. Assign binary codes to each leaf node according to their root-to-leaf path.
优先级队列应设计为最小优先级队列,即频率最低的节点应首先出现。对于处理等频项目,使用一些其他标准(例如字母顺序)作为打破平局。与编码和解码的打破平衡标准保持一致。
答案 1 :(得分:2)
一旦你拥有你的树,那么它就是一个任意选择,分配0和1如何分配给道路上每个分叉的两个分支。因此,如果没有办法使该指派具有规范性,那么如何将比特分配给每个符号就没有“正确答案”,例如: r
必须是011
。 r
可以是任何三位值。 (虽然这组频率的长度必须为3位。)
重要的是解码器获得与编码器相同的0和1分配。您可以直接发送代码,也可以发送长度并以规范方式分配0和1。例如,zip,gzip,png等中使用的压缩算法仅发送每个符号的位数。然后从最小长度开始,该长度的所有符号被分配从0开始的代码。符号按顺序分配代码,符号按其表示整数排序。例如。字符的ASCII排序顺序。对于下一个长度,在右侧添加位,并继续进行代码计数。这确保了正确的前缀码,从左到右解码。
所以在这种情况下,代码长度为:
2: _
3: a, e, r
4: d, f, n
5: b, h, t
6: i, k, o, s, u, v
所以我们得到(在每个长度内按字母顺序排列符号):
_: 00
a: 010
e: 011
r: 100
d: 1010
f: 1011
n: 1100
b: 11010
h: 11011
t: 11100
i: 111010
k: 111011
o: 111100
s: 111101
u: 111110
v: 111111
这里的比特分配与三本符号中的两个符号不同。作为其他完美的规范前缀代码选择的示例,您可以反转所有位,或者可以反转位列的任何子集。例如。你可以颠倒整个第一列。您可以更改每个长度中的符号顺序。您可以反转位顺序。实际上,zip等以相反的顺序存储上面显示的位,因此首先从最低有效位(即从右到左)进行解码。