【问题标题】:Bit Array in C++C++ 中的位数组
【发布时间】:2010-09-27 17:56:50
【问题描述】:

在处理 Project Euler 问题时,我经常需要大型 (> 10**7) 位数组。

我的正常做法是:

bool* sieve = new bool[N];

bool sieve[N];

当 N = 1,000,000 时,我的程序使用 1 兆字节(8 * 1,000,000 位)。

有没有比 c++ 中的 bool 更有效的方式来使用存储位数组?

【问题讨论】:

标签: c++ arrays bit


【解决方案1】:

使用std::bitset(如果N 是常量),否则使用其他人提到的std::vector<bool>(但不要忘记阅读Herb Sutter 的this excellent article

bitset 是一个特殊的容器类,旨在存储位(元素只有两个可能的值:0 或 1,真或假,...)。

该类与常规数组非常相似,但针对空间分配进行了优化:每个元素仅占用一位(比 C++ 中最小的元素类型:char 少八倍)。

编辑

Herb Sutter(在那篇文章中)提到

std::vector 不符合标准的原因是它隐藏了一些技巧以试图优化空间:而不是为每个 bool[1] 存储一个完整的 char 或 int(占用至少 8乘以空间,在具有 8 位字符的平台上),它会打包布尔值并将它们存储为单独的位(在内部表示中,例如字符)。

std::vector 强制通过将其写入标准来对所有用户进行特定优化。这不是一个好主意。不同的用户有不同的要求,现在所有vector的用户都必须付出性能代价,即使他们不想要或不需要节省空间。

编辑 2

如果您使用过 Boost,则可以使用 boost::dynamic_bitset(如果 N 在运行时已知)

【讨论】:

  • 遗憾的是,到 2021 年 11 月 24 日,指向 Sutter 文章的链接已失效。
【解决方案2】:

无论好坏,std::vector<bool> 将使用位而不是布尔值,以节省空间。因此,只需使用 std::vector,就像您一开始就应该使用的那样。

如果N是一个常量,你可以使用std::bitset

【讨论】:

    【解决方案3】:

    您可以查找std::bitsetstd::vector<bool>。通常不建议使用后者,因为尽管名称中有vector,但它实际上并不像任何其他类型的对象的向量,实际上也不符合一般容器的要求。尽管如此,它还是很有用的。

    OTOH,没有什么会(至少可靠地)将 100 万个布尔值存储在不到 100 万位中。根本无法确定。如果您的位集包含一定程度的冗余,则有各种可能有效的压缩方案(例如,LZ*、霍夫曼、算术),但如果不了解内容,就不可能肯定地说它们会有效。然而,这些中的任何一个通常只会将每个布尔/位存储在一个存储位中(加上一个一点用于簿记的开销——但这通常是一个常数,并且大约是字节到几十个最多字节)。

    【讨论】:

      【解决方案4】:

      “bool”类型不是仅使用 1 位存储的。根据您对大小的评论,每个布尔值似乎使用 1 个完整字节。

      类似 C 的方法是:

      uint8_t sieve[N/8]; //array of N/8 bytes
      

      然后逻辑或字节一起得到你所有的位:

      sieve[0] = 0x01 | 0x02; //this would turn on the first two bits
      

      在该示例中,0x01 和 0x02 是表示字节的十六进制数字。

      【讨论】:

      • 赞成,好主意,可能是,它是 N/8+1,它是位压缩数组。
      【解决方案5】:

      “bool”类型不是仅使用 1 位存储的。从您对大小的评论来看,每个 bool 似乎使用 1 个完整字节。

      类似 C 的方法是:

      uint8_t sieve[N/8]; //array of N/8 bytes
      

      数组的元素是:

      result = sieve[index / 8] || (1 << (index % 8)); 
      

      result = sieve[index >> 3] || (1 << (index & 7));
      

      在数组中设置 1:

      sieve[index >> 3] |= 1 << (index & 7);
      

      【讨论】:

        【解决方案6】:

        您可能有兴趣尝试使用BITSCAN 库作为替代方案。最近有人提出了稀疏性的扩展,我不确定你的情况,但可能是。

        【讨论】:

          【解决方案7】:

          您可以使用字节数组并对其进行索引。索引n 将在字节索引n/8 中,位#n%8。 (如果 std::bitset 由于某种原因不可用)。

          【讨论】:

            【解决方案8】:

            如果 N 在编译时已知,则使用std::bitset,否则使用boost::dynamic_bitset

            【讨论】:

              猜你喜欢
              • 2011-04-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-03-10
              • 2021-09-24
              • 2011-06-03
              • 2013-09-17
              • 1970-01-01
              相关资源
              最近更新 更多