【问题标题】:What are some alternatives to a bit array?位数组有哪些替代方案?
【发布时间】:2010-09-07 08:35:48
【问题描述】:

我有一个信息检索应用程序,它可以创建大约 10 万位的位数组。数组中“设置”位的数量变化很大,从全部清除到全部设置。目前,我使用的是直截了当的位数组 (java.util.BitSet),所以我的每个位数组都需要几兆字节。

我的计划是查看前 N 位的基数,然后决定其余部分使用什么数据结构。显然,一些数据结构更适合非常稀疏的位数组,而另一些数据结构在设置了大约一半的位时更好(当设置了大多数位时,我可以使用否定将其视为稀疏的零集)。

  • 哪些结构在每个极端情况下都可能是好的?
  • 中间有吗?

这里有一些限制或提示:

  1. 这些位仅设置一次,并按索引顺序。
  2. 我需要 100% 的准确度,所以像布隆过滤器这样的东西还不够好。
  3. 构建集合后,我需要能够高效地迭代“集合”位。
  4. 位是随机分布的,因此游程编码算法可能不会比位索引的简单列表好多少。
  5. 我正在尝试优化内存利用率,但速度仍然有一些的分量。

具有开源 Java 实现的东西是有帮助的,但不是绝对必要的。我对基础知识更感兴趣。

【问题讨论】:

    标签: data-structures information-retrieval


    【解决方案1】:

    除非数据是真正随机的并且具有对称的 1/0 分布,那么这将简单地成为一个无损数据压缩问题并且非常类似于 CCITT Group 3 压缩用于黑白(即:二进制)传真图像。 CCITT Group 3 使用霍夫曼编码方案。在传真的情况下,他们使用一组固定的霍夫曼代码,但对于给定的数据集,您可以为每个数据集生成一组特定的代码,以提高实现的压缩率。只要您只需要按顺序访问这些位,正如您所暗示的那样,这将是一种非常有效的方法。随机访问会带来一些额外的挑战,但您可能会为数组中的各个偏移点生成一个二叉搜索树索引,这样您就可以靠近所需的位置,然后从那里走进去。

    注意:即使数据是随机的,只要 1/0 分布不完全均匀,霍夫曼方案仍然有效。即分布越不均匀,压缩比越好。

    最后,如果这些比特是真正随机且均匀分布的,那么,好吧,根据先生的说法。 Claude Shannon,您将无法使用任何方案对其进行大量压缩。

    【讨论】:

    • 漂亮的解决方案。它甚至可能也很快,因为今天的内存负载非常昂贵。
    【解决方案2】:

    直截了当的无损压缩是要走的路。为了使其可搜索,您必须压缩相对较小的块并在块数组中创建索引。该索引可以包含每个块中起始位的位偏移量。

    【讨论】:

      【解决方案3】:

      快速组合证明你不能真正节省太多空间:

      假设您将 n/2 位的任意子集设置为 n 个总位中的 1 个。您有 (n 选择 n/2) 种可能性。使用Stirling's formula,这大约是 2^n / sqrt(n) * sqrt(2/pi)。如果每种可能性都同样可能,那么就没有办法给更可能的选择提供更短的表示。所以我们需要 log_2 (n 选择 n/2) 位,大约是 n - (1/2)log(n) 位。

      这不是一个很好的内存节省。例如,如果您使用 n=2^20 (1 meg),那么您只能节省大约 10 位。这不值得。

      话虽如此,任何真正有用的数据似乎也不太可能是真正随机的。如果您的数据有更多结构,可能会有更乐观的答案。

      【讨论】:

        【解决方案4】:

        感谢您的回答。这就是我要尝试动态选择正确方法的方法:

        我将收集常规位数组中的所有前 N 个命中,并根据此样本的对称性从三种方法中选择一种。

        • 如果样品高度不对称, 我将简单地将索引存储到 设置位(或者可能是距离 下一位)在列表中。
        • 如果样本高度对称, 我会继续使用传统的钻头 数组。
        • 如果样品中度 对称的,我将使用无损 像霍夫曼这样的压缩方法 编码suggested by InSciTekJeff。

        不对称、中等和对称区域之间的界限将取决于各种算法所需的时间与它们所需的空间相平衡,其中时间与空间的相对值将是一个可调整的参数。霍夫曼编码所需的空间是对称性的函数,我将通过测试对其进行描述。此外,我将测试所有三种方法以确定我的实现的时间要求。

        有可能(实际上我希望)中间压缩方法总是比列表或位数组或两者都好。也许我可以通过选择一组适用于更高或更低对称性的霍夫曼代码来鼓励这一点。然后我可以简化系统,只用两种方法。

        【讨论】:

          【解决方案5】:

          还有一个压缩思路:

          如果位数组不是很长,您可以在使用任何重复编码(例如 Huffman)之前尝试应用 Burrows-Wheeler transform。一个简单的实现将在(解)压缩期间占用 O(n^2) 内存,并在 O(n^2 log n) 时间内进行解压缩 - 几乎可以肯定还有捷径。但是,如果您的数据有任何顺序结构,这应该真的有助于 Huffman 编码。

          您也可以一次将这个想法应用于一个块,以使时间/内存使用更加实用。如果您按顺序读取/写入,一次使用一个块可以让您始终保持大部分数据结构的压缩。

          【讨论】:

            【解决方案6】:

            我强烈考虑使用范围编码代替霍夫曼编码。一般来说,范围编码可以比霍夫曼编码更有效地利用不对称性,但当字母表大小非常小时尤其如此。事实上,当“原生字母表”只是 0 和 1 时,霍夫曼获得任何压缩的唯一方法就是组合这些符号——这正是范围编码将更有效地做的事情。

            【讨论】:

            • 感谢 Antaeus,我实际上已经研究过范围编码,因为公认的答案将霍夫曼编码只是无损压缩的一个例子。然而,霍夫曼很容易实现,并且在适度不对称的输入上效果很好。对于高度不对称的输入,游程方法很好。
            【解决方案7】:

            对您来说可能为时已晚,但是有一个非常快速且内存高效的库,用于基于尝试的稀疏位数组(无损)和其他数据类型。看Judy arrays

            【讨论】:

            • 谢谢比尔。我记得以前听说过 Judy 数组,但我完全忘记了它们。我会再看看他们。
            猜你喜欢
            • 2011-03-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-01-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多