C++ 如何在C++;(用于哈夫曼编码器)?
我正在写我自己的,到目前为止,我已经创建了哈夫曼树,通过使用minHeap弹出两个最低频率的节点,创建一个链接到它们的节点,然后将新节点推回一个(起泡、冲洗、重复,直到只有一个节点) 现在我已经创建了树,但是我需要使用这棵树为每个角色分配代码。我的问题是我不知道如何在C++中存储一个数字的二进制表示。我记得读到过,无符号字符是字节的标准,但我不确定 我知道我必须反复遍历树,每当我碰到一个叶节点时,我必须指定相应的字符,不管当前代码代表的是什么路径 以下是我到目前为止的情况:C++ 如何在C++;(用于哈夫曼编码器)?,c++,binary-tree,bit-manipulation,huffman-code,tree-traversal,C++,Binary Tree,Bit Manipulation,Huffman Code,Tree Traversal,我正在写我自己的,到目前为止,我已经创建了哈夫曼树,通过使用minHeap弹出两个最低频率的节点,创建一个链接到它们的节点,然后将新节点推回一个(起泡、冲洗、重复,直到只有一个节点) 现在我已经创建了树,但是我需要使用这棵树为每个角色分配代码。我的问题是我不知道如何在C++中存储一个数字的二进制表示。我记得读到过,无符号字符是字节的标准,但我不确定 我知道我必须反复遍历树,每当我碰到一个叶节点时,我必须指定相应的字符,不管当前代码代表的是什么路径 以下是我到目前为止的情况: void trave
void traverseFullTree(huffmanNode* root, unsigned char curCode, unsigned char &codeBook){
if(root->leftChild == 0 && root->rightChild == 0){ //you are at a leaf node, assign curCode to root's character
codeBook[(int)root->character] = curCode;
}else{ //root has children, recurse into them with the currentCodes updated for right and left branch
traverseFullTree(root->leftChild, **CURRENT CODE SHIFTED WITH A 0**, codeBook );
traverseFullTree(root->rightChild, **CURRENT CODE SHIFTED WITH A 1**, codeBook);
}
return 0;
}
CodeBook是我的数组,它最多可以存放256个字符的代码(对于ASCII中的每个可能的字符),但我只将代码实际分配给树中出现的值
我不确定这是否是遍历我的哈夫曼树的正确方法,但这似乎立即起作用(尽管我还没有测试它)。还有,我如何调用整个树的根的遍历函数,其中没有0或1(树的最顶端)
我应该改为使用字符串并在字符串后面附加零或1吗?因为计算机是二进制的。。。C/C++中的所有数字都已经是二进制格式
int a = 10;
变量a
是二进制数
您要了解的是位操作,例如&|>
使用哈夫曼编码,您可以将数据打包成一个字节数组
我已经很久没有写C了,所以这是一个“即兴”的伪代码
完全未经测试——但应该给你正确的想法
char buffer[1000]; // This is the buffer we are writing to -- calc the size out ahead of time or build it dynamically as go with malloc/ remalloc.
void set_bit(bit_position) {
int byte = bit_position / 8;
int bit = bit_position % 8;
// From http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c
byte |= 1 << bit;
}
void clear_bit(bit_position) {
int byte = bit_position / 8;
int bit = bit_position % 8;
// From http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c
bite &= ~(1 << bit);
}
// and in your loop, you'd just call these functions to set the bit number.
set_bit(0);
clear_bit(1);
char缓冲区[1000];//这就是我们正在写入的缓冲区——提前计算大小,或者使用malloc/remalloc动态构建它。
无效设置\u位(位\u位置){
int字节=位位置/8;
int位=位位置%8;
//从http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c
字节|=1由于curCode只有0和1作为其值,因此位集可能适合您的需要。它既方便又节省内存。参考此:
只需对代码进行一点更改:
void traverseFullTree(huffmanNode* root, unsigned char curCode, BitSet<N> &codeBook){
if(root->leftChild == 0 && root->rightChild == 0){ //you are at a leaf node, assign curCode to root's character
codeBook[(int)root->character] = curCode;
}else{ //root has children, recurse into them with the currentCodes updated for right and left branch
traverseFullTree(root->leftChild, **CURRENT CODE SHIFTED WITH A 0**, codeBook );
traverseFullTree(root->rightChild, **CURRENT CODE SHIFTED WITH A 1**, codeBook);
}
return 0;
}
void遍历树(huffmanode*root、无符号字符curCode、位集和码本){
如果(root->leftChild==0&&root->rightChild==0){//您位于叶节点,请将curCode分配给root的字符
代码本[(int)根->字符]=curCode;
}否则{//root有子级,使用为right和left分支更新的currentCodes递归到它们中
遍历树(root->leftChild,**当前代码以0**移位,码本);
遍历树(root->rightChild,**当前代码以1**移位,代码本);
}
返回0;
}
请不要使用字符串
您可以将代码本表示为两个整数数组,一个包含代码的位长度,另一个包含代码本身。这有一个问题:如果代码长度大于整数,该怎么办?解决方案就是不要这样做。最大代码长度较短(比如15)由于各种原因,在哈夫曼编码的大多数实际应用中使用了一种技巧
我建议使用,这稍微简化了树遍历:您只需要长度,因此不必跟踪当前代码。使用规范的哈夫曼代码,您可以轻松地从长度生成代码
如果您使用的是规范代码,则可以让代码比整数宽,因为高位无论如何都是零。但是,限制长度仍然是一个好主意。最大长度较短(不太短,这将限制压缩,但大约为16)使您能够使用最简单的方法,即简单的单级表
将代码长度限制在25或更少也略微简化了编码,它允许您使用32位整数作为“缓冲区”并逐字节清空,而无需对缓冲区容纳少于8位但编码当前符号会溢出的情况进行任何特殊处理(因为完全避免了这种情况——在最坏的情况下,缓冲区中有7位,您尝试编码一个25位的符号,这很好)
类似这样的东西(没有以任何方式进行测试)
uint32\u t buffer=0;
int bufbits=0;
对于(int i=0;i
你可以简单地使用
#包括
#包括
int main(){
INTA=42;
std::位集bs(a);
std::是的,我知道这一点,但如果我使用位操作,我的所有字符不是都有前导零吗?哈夫曼编码应该利用这样一个事实,即你不需要所有的8位,对吗?@user0123——为你抛出一些P代码。我想为了测试/调试的目的,你可以建立一个1和0的字符串,因为这是far更容易调试(字符串打印得很好),但是如果你真的想生成可用的输出,你可以使用上面的想法。@user2485710——没错。如果你想旋转位,C
是一种很棒的语言。如果你想了解发生了什么,C
是一种很棒的语言。事实上,C++
主要是一组超级的C
说明了C
有多有用。我会使用这个项目,但这个项目是用于数据结构类的,我不允许使用STL:(@user0123没关系。只是想帮点忙。
uint32_t buffer = 0;
int bufbits = 0;
for (int i = 0; i < symbolCount; i++)
{
int s = symbols[i];
buffer <<= lengths[s]; // make room for the bits
bufbits += lengths[s]; // buffer got longer
buffer |= values[s]; // put in the bits corresponding to the symbol
while (bufbits >= 8) // as long as there is at least a byte in the buffer
{
bufbits -= 8; // forget it's there
writeByte((buffer >> bufbits) & 0xFF); // and save it
}
}
#include <iostream>
#include <bitset>
int main() {
int a = 42;
std::bitset<(sizeof(int) * 8)> bs(a);
std::cout << bs.to_string() << "\n";
std::cout << bs.to_ulong() << "\n";
return (0);
}