【问题标题】:problem in saving Huffman Code?保存霍夫曼代码的问题?
【发布时间】:2011-07-07 19:18:11
【问题描述】:

我想将霍夫曼代码保存到文件中。我怎样才能做到这一点? 我将霍夫曼代码保存到一个字符串中,但生成的文件的大小比原始文件大。

【问题讨论】:

  • 霍夫曼编码产生可变位长编码。如果您在输出时不将代码打包在一起,那么 5 位代码只需要 5 位,您将不会得到压缩。您需要创建一个可以一次填充 n 位的字节缓冲区,其中 n 不是 8 的倍数。
  • 我不明白“您需要创建一个可以一次填充 n 位的字节缓冲区,其中 n 不是 8 的倍数” ?????怎么办?
  • 您必须手动设置位,方法是将您的数据编码为其他数据类型(如 int)或使用其他库作为位集。
  • 静态霍夫曼算法,我想。对于动态霍夫曼算法,你不需要存储任何东西:)
  • @antlersoft 如果编码数据的总位数不是 8 的倍数怎么办?不能简单地将 0 位附加到文件末尾以完成最后一个字节......读取压缩文件时虚拟零也会被解码......

标签: c++ c huffman-code


【解决方案1】:

一个非常简单的方法是一次写入一个位,如下所示:

unsigned char acc; // Accumulator of bit waiting to be written
int bitcount;      // How many bits are aready present in the accumulator

// write a single bit (0/1)
void writebit(int bit)
{
    acc |= (bit << bitcount);
    if (++bitcount == 8)
    {
        writebyte(acc);
        acc = 0;
        bitcount = 0;
    }
}

读回一个位,过程是对称的

unsigned char acc;   // bits waiting to be extracted
int bitcount;        // how many bits are still available in acc

int readbit()
{
   if (bitcount == 0)
   {
       bitcount = 8;
       acc = readbyte();
   }
   --bitcount;
   return (acc >> (7 - bitcount)) & 1;
}

当然,这只是最简单的方法,但我会等到您第一次能够正确保存和加载编码数据之后再担心代码速度。

示例:

假设您有以下霍夫曼编码符号

A - 0
B - 10
C - 110
D - 111

你想对序列进行编码

A B A A C D A D B B

然后你会按顺序调用

writebit(0);                           // A
writebit(1); writebit(0);              // B
writebit(0);                           // A
writebit(0);                           // A
writebit(1); writebit(1); writebit(0); // C
writebit(1); writebit(1); writebit(1); // D
writebit(0);                           // A
writebit(1); writebit(0);              // B
writebit(1); writebit(0);              // B

因此实际写入的字节数为

(01100010) = 0x62
(01010111) = 0x57

(请注意,显示的代码从最低有效位开始,即如果要识别符号,则应从右到左读取括号内的位序列)。

【讨论】:

  • 我想将霍夫曼代码保存到文件中。我怎样才能做到这一点?我将霍夫曼代码保存到一个字符串中,但生成的文件的大小大于原始文件。如果文件压缩正确,如何读取提取?我的意思是如果 char 'a' 具有“11”霍夫曼代码而 b 具有“011”霍夫曼代码(两者都具有相同的 ASCII 代码)我们如何理解哪个是真实的 'a' 或 'b'?
  • 我添加了一个例子,说明一小段霍夫曼编码符号的输出字节数。在读取位编码流时,您不会考虑字节,而是考虑位......单个符号可能恰好是一个字节的一部分,而另一个字节的一部分(但这在我的示例中不会发生)。
【解决方案2】:

我相信您要保存的是一串 1 和 0。真正的霍夫曼代码需要以二进制形式保存,然后再进行解析。如果您只是将输出保存为字符串,那么您就违背了霍夫曼代码的目的,每个 0 和 1 都是 8 位而不是 1。

【讨论】:

  • 我认为没有理由对此表示反对。这是学生和不熟悉二进制存储的人非常普遍的问题。我个人对此答案 +1。
  • @Zéychin 这是学生中很常见的问题,就像几年前的我一样。 ;)
  • 没错。不是每个人都具有类似计算机的思维过程的天赋。 (这也是一件好事,因为我讨厌 SEGFAULT。:P。)
  • 值得一说,虽然没有什么让我认为 OP 确实以这种方式存储这些位,“作为”字符串 - 他说他将它们“存储”到一个字符串中,这让我认为字符串只是一个“缓冲区”的同义词;但万一我错了,+1 想象一个不太可能的错误
【解决方案3】:

您可能正在为每个模式/字母保存整个字节。

假设 e 是最常见的字母。它将有一个 0 位模式。

假设 z 是最不常见的字母,它将具有以 1 开头的某种模式。我们将其分配为 1111 111。

你要写的文件是这样的:

0111 1111

你可能正在写这个:

0000 0000 0111 1111.

您需要利用按位运算来执行此操作。

【讨论】:

  • 公平地说,这是微不足道的部分。将运行长度与实际运行一起以紧凑的方式存储有点困难。
  • 好吧,公平地说,它恰当地回答了这个问题。这种存储数据的方式会导致文件比原始文件短。您提供的参考资料也很棒,但对于那些一开始可能不了解编码树的人来说可能有点不知所措。
  • @BLindly:不需要。在正确编码的霍夫曼编码位序列中,您知道符号何时完成,因为您到达了霍夫曼树中的叶子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-24
  • 1970-01-01
  • 2011-08-02
  • 1970-01-01
相关资源
最近更新 更多