【问题标题】:Efficient container for bits高效的位容器
【发布时间】:2009-08-10 01:55:11
【问题描述】:

我有一个位数组,它在某些部分非常密集,而在其他部分非常稀疏。该数组可以达到 2**32 位。我将它变成一堆包含偏移量和长度的元组,以使其在内存中处理更有效。但是,有时这对于 10101010100011 之类的东西效率较低。关于将其存储在内存中的好方法有什么想法吗?

【问题讨论】:

  • 你想在数据结构上高效地支持什么类型的操作?

标签: arrays data-structures performance bit


【解决方案1】:

如果我理解正确,您使用 (offset, length) 的元组来表示 1 位的运行?如果是这样,更好的方法是使用打包位域的运行。对于密集区域,您会得到一个非常有效的数组,而在非密集区域,您会得到隐含的零。例如,在 C++ 中,表示可能如下所示:

// The map key is the offset; the vector's length gives you the length
std::map<unsigned int, std::vector<uint32_t> >

查找将包括在相关位位置之前找到密钥,并查看该位是否落在其向量中。如果是,请使用向量中的值。否则,返回 0。例如:

typedef std::map<unsigned int, std::vector<uint32_t> > bitmap; // for convenience
typedef std::vector<uint32_t> bitfield; // also convenience

bool get_bit(const bitmap &bm, unsigned int idx) {
  unsigned int offset = idx / 32;
  bitmap::const_iterator it = bm.upper_bound(offset);

  // bm is the element /after/ the one we want
  if (it == bm.begin()) {
    // but it's the first, so we don't have the target element
    return false;
  }

  it--;

  // make offset be relative to this element start
  offset -= it.first;
  // does our bit fall within this element?
  if (offset >= it.second.size())
    return false; // nope

  unsigned long bf = it.second[offset];
  // extract the bit of interest
  return (bf & (1 << (offset % 32))) != 0;
}

【讨论】:

  • 对不起,但我不确定这是如何工作的。向量包含什么?
  • 我添加了一个代码示例 - 基本上,向量包含一系列 uint32_ts,每个都给出位数组的 32 位切片
  • 关于您的代码示例的问题:这里是否存在非一错误?你返回false if (offset > it.second.size()),所以如果offset == it.second.size(),你不返回,然后你看it.second[offset]。你应该写 >= 而不是 > 吗?
【解决方案2】:

了解更多信息会有所帮助。 “非常稀疏/密集”是指数百万个连续的 0/1,还是指 0 非常接近 0 或 1 的局部(如何局部?)比例?一个或另一个价值占主导地位吗?是否有任何模式可以使游程编码有效?你将如何使用这个数据结构? (随机访问?访问索引的分布是什么样的?大块永远不会或很少访问?)

我只能猜测您不会以每秒数十亿位的速率随机访问和修改所有 40 亿位。除非它在局部级别上非常稀疏/密集(例如任何一百万个连续位可能是相同的,除了 5 或 10 位)或充满大规模重复或模式,我的直觉是数据结构的选择取决于更多关于如何使用数组而不是数据的性质。

【讨论】:

    【解决方案3】:

    如何构建事物将取决于您的数据是什么。为了尝试表示大量数据,您需要长时间运行零或一。这将消除重新呈现它的需要。如果不是这种情况,并且您的 1 和 0 的数量大致相同,那么使用所有内存会更好。

    将其视为压缩问题可能会有所帮助。为了使压缩有效,必须有一种模式(或在整个空间中使用的一组限制项目)和不均匀的分布才能使压缩起作用。如果所有元素都被使用并均匀分布,则很难进行压缩,或者可能会占用比实际数据更多的空间。

    如果只有零和一的运行(不止一个),使用偏移量和长度可能会有意义。如果运行不一致,您可以将位复制为具有偏移量、长度和值的位数组。

    上述方法的效率取决于您是否有大量的 1 或 0。您需要小心确保您没有使用更多的内存来表示您的内存,而只是使用内存本身(即您使用更多的内存来表示内存,然后只是将其放入内存中)。

    【讨论】:

      【解决方案4】:

      查看bison source code。看看 biset 的实现。它提供了多种实现方式来处理具有不同密度的位数组。

      【讨论】:

        【解决方案5】:

        您打算一次记住其中的多少?

        据我所知,2**32 位 = 512M,只有半个演出,现在这不是很多内存。你有什么更好的办法吗?

        假设您的服务器有足够的内存,在启动时将其全部分配,然后将其保存在内存中,网络处理线程可以在恒定时间内以几条指令执行 - 它应该能够跟上任何工作负载。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-08-05
          • 1970-01-01
          • 2015-05-17
          • 2017-02-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多