高效的钻头容器

时间:2009-08-10 01:55:11

标签: arrays data-structures performance bit

我有一个阵列,在某些部分可能非常密集,而在其他部分则非常稀疏。该阵列可以达到2 ** 32位。我将它变成一堆包含偏移和长度的元组,以使其在内存中处理更有效。然而,对于像10101010100011这样的事情,这有时效率较低。有关将这种存储在内存中的好方法的任何想法吗?

5 个答案:

答案 0 :(得分:2)

如果我理解正确,你使用(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;
}

答案 1 :(得分:1)

了解更多信息会有所帮助。通过“非常稀疏/密集”,你的意思是数百万个连续的零/一个,或者你的意思是本地(如何本地?)0的比例非常接近0或1?一个或另一个值是否占主导地位?是否有任何可能使运行长度编码有效的模式?您将如何使用此数据结构? (随机访问?访问索引的分布是什么?是不是很少或很少访问的巨大块?)

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

答案 2 :(得分:0)

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

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

如果只有0和1的运行,(更多只有一个),使用偏移量和长度可能会有所帮助。如果存在不一致的运行,则可以将这些位复制为具有偏移量,长度和值的位数组。

以上的效率取决于你是否有大量的1或0。你需要小心确保你没有使用更多的内存来重复你的内存,然后只使用内存本身(即你使用更多的内存来代表内存然后只是将它放入内存)。

答案 3 :(得分:0)

结帐bison source code。看看biset的实现。它提供了几种实现方式来处理具有不同密度的位阵列。

答案 4 :(得分:0)

您打算一次保留多少内容?

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

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