读取霍夫曼树并解码消息

时间:2017-04-27 15:27:36

标签: c++ tree compression bit huffman-code

我正在尝试用С++实现一个霍夫曼压缩器。

简而言之,我有5个班级:

  1. HuffmanTree - 代表树形结构

  2. TreeNode - 代表树形结构

  3. HuffmanArchiver - 压缩/解压缩等。

  4. BitStringWrite - 写位。

  5. BitStringRead - 阅读比特。

  6. (完整实施在此处:headerscpp's

    我可以构建一个代码表并对二进制文件进行编码,但是我有一些关于读/写和解码阶段的问题。

    当我进行编码阶段时,首先我将Huffman树保存在我的新文件中,如下所示:

    void Archiver::encodeTree(BitStringWrite& bw, TreeNode* node){
        if (node -> isLeaf()) {
            bw.writeBit(1);
            char symb = node->getChar();
            bw.getStream().write(&symb, sizeof(symb));
        }
        else {
            bw.writeBit(0);
            encodeTree(bw, node->getLeftTree());
            encodeTree(bw, node->getRightTree());
        }
    }
    

    bw这是类BitStringWrite的一个实例,它实现如下:

    BitStringWrite::BitStringWrite(std::ostream &_out_f) : _byte(0), _pos(0), _out_f(_out_f) {}
    
    void BitStringWrite::writeBit(bool bit) {
       if (_pos == 8)
           flush();
       if (bit == 1) {
           _byte |= (1 <<   (7 - _pos));
       }
       _pos++;
    }
    
    void BitStringWrite::writeByte(char b){
       for(int i = 0; i < 8; i++)
           this -> writeBit((b >> i) & 1); //?????
    }
    
    void BitStringWrite::flush() {
       if (_pos != 0) {
           _out_f.write(&_byte, sizeof(char));
           _pos = 0;
           _byte = 0;
       }
    }
    
    std::ostream& BitStringWrite::getStream(){
        return _out_f;
    }
    

    我在writeByte实施中不确定,但这里的主要问题是,如果我已经有writeByte,我可能想要实现istream::write函数吗?

    例如

    >cat test.in aaaabc

    buildTable函数将生成:a = 1b = 010c = 00= 011

    (似乎最后一个符号只是\n)。

    xxd -b test.out 00000000: 01100011 01100010 00001010 01100001 00101111 11101000 cb.a/. 00000006: 01101100

    注意,编码消息从第五个字节的最后一位开始。前五个(几乎)字节表示结构树。

    好的,似乎编码阶段正在运行。现在让我们进入解码阶段。

    解码阶段的主要功能是decompress。它调用decodeTree函数对Huffman树进行解码,然后根据该树生成代码表,然后对文本进行解码。

    函数decodeTree无法正常运行:

    TreeNode* Archiver::decodeTree(BitStringRead& br, TreeNode* cur){
        if (br.readBit()) {
            return new TreeNode(br.readByte(), 0, false, NULL, NULL);
        }
        else {
            TreeNode* left = decodeTree(br, cur-> getLeftTree());
            TreeNode* right = decodeTree(br, cur-> getRightTree());
            decodeTree(br, cur-> getRightTree());
            return new TreeNode(0, 0, false, left, right);
        }
    }
    

    我认为主要原因是因为它无法使用br,类BitStringRead的实例来正确读取树结构。

    看看它是如何实现的:

    BitStringRead::BitStringRead(std::istream &_in_f) : _pos(8), _in_f(_in_f) {}
    
    bool BitStringRead::readBit() {
        if (_pos == 8) {
            _in_f.read(&_byte, sizeof(char));
            _pos = 0;
        }
        return (_byte >> _pos++) & (char)1;
    }
    
    char BitStringRead::readByte() { 
        char sym = (char)0;
        for (int i = 0; i < 8; i++){     
           sym |= ((1 & readBit()) << (i));
        }
        return sym;
     }
    

    假设我们在文件的开头,我有一个字节0001 0110。我第一次调用readBit函数。它读取第一个8位。然后我再调用它3次,它没有读取任何内容,只是返回这些位的值。字符串中的第一个1表示叶节点,我知道在叶节点之后有一个符号,所以我读了它。

    由于readBit实现,我认为它从第9位而不是第4位开始读取。

0 个答案:

没有答案