C ++:从位构建迭代器

时间:2010-03-07 10:42:11

标签: c++ algorithm iterator bitmap

我有一个位图,并希望返回设置位位置的迭代器。现在我只是走完整个位图,如果设置了位,那么我提供下一个位置。我相信这可以更有效地完成:例如,为单字节中的每个位组合构建静态数组并返回位置向量。这不能用于整个int,因为数组太大了。但也许有更好的解决方案?你知道任何智能算法吗?

1 个答案:

答案 0 :(得分:5)

我可以提出几个想法。

  • 结果显示现代CPU具有专用指令,用于查找32位或64位字中的下一个设置位。
  • 我非常喜欢你从准备好的高效的每字节迷你迭代器构建整个位图的迭代器的想法,这真的很酷,我很惊讶我以前从未见过它!
  • 如果您的位图非常稀疏,您可以用其他形式表示它,例如平衡树,其中迭代算法是众所周知的。
  • 如果你的位图稀疏但是有密集的区域(听起来很奇怪,但我遇到的情况确实如此),请使用小型(32位或64位)位图的平衡树并使用树的组合迭代算法和单词的位。
  • 为了避免显式树的内存开销,请使用隐式树,就像规范的heapsort算法一样。在你的bitset准备就绪并且不会发生变异之后,在它上面建立一个“金字塔”,其中level(N + 1)[i] = level(N)[2 * i] |电平(N)[2 * I + 1]。这将允许您快速跳过bitset的无人区域,并且迭代将以类似于迭代常规二叉树的方式完成。你也可以从字节等开始建立一个居住金字塔:这一切都取决于你的位置有多稀疏。
  • 有一个众所周知的比特技巧,用于查找单词中前导零的数量;例如,请参阅java标准库的code
  • 使用被动迭代器而非活动迭代器t.i可能会获得很多性能。而不是begin()和operator ++(),为你的bitset提供foreach(F)函数,其中F有operator()。如果需要提前终止的被动迭代,请使F的operator()返回一个布尔值,表示是否请求终止。

编辑:我无法抗拒尝试为字节准备迭代器的方法。我在C#2.0中编写了一个代码生成器,它生成以下形式的代码:

IEnumerable<int> bits(byte[] bytes) {
    for(int i=0; i<bytes.Length; ++i) {
        int oi=8*i;
        switch(bytes[i]) {
            ....
            case 74: yield return oi+1; yield return oi+4; yield return oi+6; break;
            ....
        }
    }
}

我将计算随机50%填充字节数组(10Mb)的位的性能与完全不使用迭代器的代码的性能进行了比较,并且包含两个循环:

for (int i = 0; i < bytes.Length; ++i) {
    byte b = bytes[i];
    for (int j = 7; j >= 0; --j) {
        if (((int)b & (1 << j)) != 0) s++;
    }
}

第二个代码片段比第一个代码片段快1.66倍(~1.5s vs~2.5s)。我认为稀疏位数组甚至可能使第一个代码胜过第二个代码。