【问题标题】:Last byte in Huffman compression霍夫曼压缩中的最后一个字节
【发布时间】:2013-01-18 00:39:41
【问题描述】:

我想知道在 Huffman Copression 中处理最后一个字节的最佳方法是什么。我在 C++ 中有一些不错的代码,可以很好地压缩文本文件,但目前我必须向我的编码文件写入编码字符的数量(嗯,它等于输入文件的大小),因为不知道如何处理最后一个字节更好。

例如,最后一个要压缩的字符是'a',代码是011,我刚刚开始写新字节,所以最后一个字节看起来像: 011 + 一些 5 位垃圾,例如最后我将它们设为零。 当我对这个编码文件进行编码时,可能会发生代码 00000(或更少的零)是某些字符的代码,所以我的编码文件末尾会有一些垃圾字符。

正如我在第一段中所写,我通过在编码文件中保存输入文件的字符数来避免这种情况,并且在编码时,我正在读取编码文件以达到该数字(不是 EndOfFile,不要得到到那些示例 5 个零)。 这不是很有效,编码文件的大小会增加。

我怎样才能更好地处理这个问题?

【问题讨论】:

    标签: algorithm compression ascii eof huffman-code


    【解决方案1】:

    我知道这是一个老问题,但仍然有一个替代方案,所以它可能会对某人有所帮助。

    当您将压缩文件写入输出时,您可能有一些整数来跟踪您在当前字节中的位置(用于位移)。

    char c, p;
    p = '\0';
    int curr = 7;
    while (infile.get(c))
    {
        std::string trav = GetTraversal(c);
        for (int i = 0; i < trav.size(); i++)
        {
            if (trav[i] == '1')
                p += (1 << curr);
            if (--curr < 0)
            {
                outfile.put(p);
                p = '\0';
                curr = 7;
            }
        }
    }
    if (curr < 7)
        outfile.put(p);
    

    在这个块的末尾,(curr+1)%8 等于最后一个数据字节中的垃圾比特数。然后,您可以将其存储为最后一个额外的字节,并在解压缩时记住它。

    【讨论】:

      【解决方案2】:

      您的方法(将编码字节数写入文件)是一种完全合理的方法。如果您想尝试不同的途径,您可以考虑发明一个新的“伪 EOF”字符来标记输入的结束(我将其表示为 &square;)。每当您想压缩字符串 s 时,您都可以压缩字符串 s&square;。这意味着,当您构建编码树时,您将包含 &square; 的一份副本。字符,以便您对 &square; 具有唯一的编码。然后,当您将字符串写入文件时,您将照常写出字符串的位字符,然后写出 &square; 的位模式。如果有剩余位,您可以随意设置它们。

      这种方法的优点是,当您解码文件时,如果您在任何时候发现 &square;字符,您可以立即停止解码位,因为您知道您已经到达文件末尾。这不需要您存储在任何地方写出的字节数 - 编码隐含地标记了它自己的端点。

      此设置的缺点是它可能会增加某些字符使用的位模式的长度,因为您需要将位模式分配给 &square;除了所有其他字符。

      我教授一门编程入门课程,我们将 Huffman 编码作为我们的一项任务。我们让学生使用上述方法,因为它比在文件内容之前写出位数或字节数要容易一些。有关更多详细信息,您可以查看课程中的this handoutthese lecture slides

      希望这会有所帮助!

      【讨论】:

      • 确实没有缺点,因为您可以证明这不会比编码长度占用更多位。
      • @MarkAdler- 你有这方面的参考吗?我经常想知道这一点,但我从未见过正式的证明。
      • 我不记得我在哪里看到的。我去找找。
      • 感谢您的回答。但是为伪EOF“牺牲”一个字符的想法意味着,当它出现在文本中时,它会毁掉一切。我知道许多 ASCII 字符根本没有使用,但我真的很想确定,我可以编码/压缩每个 ASCII 字符,然后呢?关于我的方法:当文本文件大于 sizeof long 时(嗯,可能 ;-D )会崩溃
      • @Kuba- 你不会通过为伪 EOF 牺牲一个字符来做到这一点。相反,您会选择一个非字符值(例如,INT_MAX)并假装它是一个字符,因为该值不能出现在任何字符串中。我认为最简单的方法是对int 类型的值而不是char 类型的值进行所有编码,因为您始终可以将char 编码为int,然后可以编码额外的值,例如伪 EOF 作为int 也是如此。这有意义吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多