生成'n'二进制前缀码的算法

时间:2011-09-06 15:54:32

标签: algorithm language-agnostic huffman-code

Prefix Code是一组代码,因此没有代码是另一个代码的前缀。例如,以下集合是前缀代码:

10
11
000
001
0100
0101
0110
0111

拥有n = 8个成员。我认为这些通常是用某种类型的霍夫曼树创建的。

我的问题是:你能帮我创建一个能够生成带'n'成员的二进制前缀代码的函数吗?

这样的事情:

list<int> GenerateBinaryPrefixCodes(int n);

此外,要求是在总比特最小化的意义上它是“最优的”。

我更喜欢用C / C ++ / C#/类似的答案。这不是真正的功课,但我用这种方式标记它,因为它听起来像是一个很好的hw问题。

谢谢!

6 个答案:

答案 0 :(得分:4)

最小化位数之和的要求等同于要求代码是每个符号出现一次的字符串的最佳霍夫曼代码。因此,只需创建一个包含 n 唯一字符的字符串,并为其生成一个霍夫曼树。 The algorithm is outlined on Wikipedia

答案 1 :(得分:4)

答案 2 :(得分:1)

n = 8的示例似乎不代表最佳解决方案。

  

10 11 000 001 0100 0101 0110 0111   总位数:26

     

000 001 010 011 100 101 110 111   总位数:24

当存在恒定频率时,最佳前缀编码将是固定长度。每个前缀代码的长度为log(n),并且是0..n-1字母表的二进制表示。

对于n不是2的幂的情况,

编辑

// generate tree
function PCode(n) {
 var a = [];
 for(var x=1; x<=n; x++) {
  a.push({"v":x});
 }
 for(var x=0; x<n-1; x++) {
  var node = {"v": null, "l": a.shift(), "r": a.shift()};
  a.push(node);  
 }
 return a.pop();
}

//print
function Print(node, s) {
 if(node["v"] != null) {
  console.log(s);
 }
 if(node["l"] != null) Print(node["l"], s + "0");
 if(node["r"] != null) Print(node["r"], s + "1");
 return;
}

//test
Print(PCode(3), "");

答案 3 :(得分:0)

请查看this C++ tutorial site。它将为您提供有用的C ++结构。我正在看到其他类似的SO问题可能会在右侧的“相关”部分提供帮助。

我之前在C中使用递归算法完成了这项工作,是的,它会成为一个很好的作业问题。

答案 4 :(得分:0)

通过构建n个叶子节点的二叉树,并且枚举树中每个这样的节点的位置(0是左分支,1是右分支),可以保证生成问题(解码的唯一性)。你是对的,霍夫曼树有这个属性。请注意,对于霍夫曼树,每个节点的权重等于其代表字符的频率,并且树构建有递归属性,节点连接的左右决策基于到该点的子节点的总和。这个累积和属性也是斐波那契分布给出霍夫曼树的最坏情况压缩的原因。

注意,霍夫曼编码对于固定字母表的变量编码是最佳的。非固定字母表的一个示例是决定将“the”视为要压缩的集合中的单个元素(而不是两个空格和每个字母一个)。

您的问题似乎与替代无关。您只需要n个元素的前缀代码,其中所有前缀代码的长度总和最小化。这与构建霍夫曼树的情况相同,其中每个元素频率为1(因为它保证了总编码字符串的最小编码,对于您来说,这等于每个编码元素的位的总和恰好一次,即最小化总数位)。注意:这保证了最小编码,但不保证最快的实现。您可能不需要为每个方法调用构建树。不幸的是,我不知道我的头脑中的实现。

答案 5 :(得分:0)

让我们用二进制表示为1x的数字对二进制字符串x进行编码。否则,0和00将映射到相同的int。

std::vector<int> GenerateBinaryPrefixCodes(int n) {
    std::vector<int> list;
    for (int i = n; i != 2 * n; ++i) list.push_back(i);
    return list;
}