【问题标题】:Compression of ASCII strings in CC中ASCII字符串的压缩
【发布时间】:2010-11-08 23:48:33
【问题描述】:

我有一些 C 代码将 ASCII 字符串作为四字节长度后跟字符串存储在内存中。字符串长度在 10-250 字节范围内。

为了减少占用,我想在运行中单独压缩每个字符串,仍然存储(压缩字符串的)长度,然后是压缩字符串。

我不想在比单个字符串更大的范围内进行压缩,因为任何字符串都可以随时读取/写入。

有哪些库/算法可用于执行此操作?

感谢您的帮助。 尼克B

【问题讨论】:

    标签: c compression


    【解决方案1】:

    ZLib 随时为您服务 - 对于字符串包含不可压缩数据的情况,它的开销非常小,它相对较快、免费并且可以轻松集成到 C 和 C++ 程序中。

    【讨论】:

      【解决方案2】:

      Zlib 在这里绝对是您的朋友,但请务必执行一些测试来检测压缩开始有益的平均字符串长度,因为压缩标头的开销很小。

      例如,您可能会发现小于 20 个字符的压缩字符串实际上更大,因此只压缩较长的字符串。

      【讨论】:

      • 如果你可以留出 1 位的大小字段来标记字符串是否被压缩,你甚至不必猜测:只需尝试压缩每个字符串。如果它变小,请将其压缩存储。如果没有,请将其未压缩存储。这大致是 PKZIP 允许的(我假设其他压缩容器,只是 PKZIP 是我碰巧实现过的一个)。不幸的是,10-250 的大小范围不能有效地接纳 8 位架构上的“备用”位。
      【解决方案3】:

      为什么在字符串长度为 10-250 字节时使用 4 字节长度,使用 1 字节长度可以为每个字符串节省 3 个字节。

      数据是否仅是文本数据,即 0-9 A-z 或某些子集?如果是这样,重新编码它以使用该子集并为每个字符节省一些位。

      现在看看 Huffman 编码部分和 lempel-zev 部分中的 http://gnosis.cx/publish/programming/compression_primer.html

      这应该让你开始。

      【讨论】:

        【解决方案4】:

        我不确定 zlib 或 LZW 压缩方法在单独压缩小于 250 字节的短字符串的情况下是否能正常工作。两者通常都需要创建一个相当大的字典才能看到显着的压缩增益。

        也许是简单的 Huffman 编码,使用固定的编码树,或者在字符串的所有实例之间共享一个?另外,你见过 80 年代内存受限的微型计算机上用于压缩短字符串的 ZSCII 编码吗?

        link text

        【讨论】:

          【解决方案5】:

          大多数压缩算法都不能很好地处理短字符串。 以下是一些旨在压缩短英文文本字符串的压缩算法。 虽然他们可以处理明文字符串中的任意字节, 这样的字节通常使“压缩”数据比明文更长。 因此,压缩器最好将“不可压缩”数据原封不动地存储并在此类数据上设置“文字”标志(正如 Steve Jessop 所建议的那样)。

          • “base 40 编码”:最大压缩比 3:2
          • “Zork 信息交换标准代码”(ZSCII):最大压缩比 3:2
          • byte pair compression:最大压缩比 2:1
          • 在所有字符串之间共享的静态 Huf​​fman 表(如 cygil 所建议的那样)。
            • 理想情况下,由所有实际数据的确切字符频率形成。
            • Varicode:最大压缩比 2:1
          • PalmDoc compression(字节对压缩 + LZ77 的简单变体)。

          【讨论】:

            【解决方案6】:

            当使用像这样的多个字符串时,可以通过将它们与\0s(1 个字节)连接在一起并使用查找函数来避免每个字符串(每个字符串 4 或 8 个字节)的指针开销。

            #include <stdio.h>
            
            static const char strings[]="hello\0world\0test";
            
            char * nthstring(const char *s, unsigned n){
                while(n--)
                    while(*s++)
                    ;
                return s;
            }
            int main(void) {
                printf("%s\n",nthstring(strings,1));
                return 0;
            }
            

            但是,如果字符串长度小于 UCHAR_MAX,您可以通过使用零字节占位符来存储长度来优化查找(在开头加上 1 个额外的长度)这仅花费 1 个额外的数据字节,但可以节省大量的条件跳转和查找函数中的增量。

            #include <stdio.h>
            /* each "string" is prefixed with its octal length */
            static const char lenstrings[]="\05hello\05world\04test";
            
            char * ithstring(const char *s, unsigned n){
                while(n--){
                    s+=*s+1;
                }
                return s;
            }
            int main(void) {
                char *s=ithstring(lenstrings,1);
                /* use the length because we don't have terminating \0 */
                printf ("%.*s",(unsigned char)*s,s+1);
                //write(1,s+1,(unsigned char)*s); //POSIX variation via <unistd.h>
                return 0;
            }
            

            对于这两种变体,最好先保留最常用的字符串;但是,第二种方法将允许您使用压缩数据(选择最适合您的数据的方法 - David Cary's answer 有一个可行的解决方案列表),只要您将长度分隔符调整为压缩长度。

            注意:要从标准压缩器中获得最大压缩,您可能希望将其标头的长度字段修改为 unsigned char(或 unsigned short,如果字符串长度超过 256 但不超过 65536 字节),因为大多数他们将尝试支持大文件的压缩(这可以为每个字符串节省 3-7 个字节)

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-05-12
              • 2011-11-12
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多