Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/85.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在C++;(用于哈夫曼编码器)?_C++_Binary Tree_Bit Manipulation_Huffman Code_Tree Traversal - Fatal编程技术网

C++ 如何在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

我正在写我自己的,到目前为止,我已经创建了哈夫曼树,通过使用minHeap弹出两个最低频率的节点,创建一个链接到它们的节点,然后将新节点推回一个(起泡、冲洗、重复,直到只有一个节点)

现在我已经创建了树,但是我需要使用这棵树为每个角色分配代码。我的问题是我不知道如何在C++中存储一个数字的二进制表示。我记得读到过,无符号字符是字节的标准,但我不确定

我知道我必须反复遍历树,每当我碰到一个叶节点时,我必须指定相应的字符,不管当前代码代表的是什么路径

以下是我到目前为止的情况:

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);
}