【问题标题】:C++: building iterator from bitsC++:从位构建迭代器
【发布时间】:2010-03-07 10:42:11
【问题描述】:

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

【问题讨论】:

    标签: c++ algorithm iterator bitmap


    【解决方案1】:

    我可以提出几个想法。

    • 事实证明,现代 CPU 有专门的指令来查找 32 位或 64 位字中的下一个设置位。
    • 我非常喜欢您从准备好的高效的每字节迷你迭代器构建整个位图的迭代器的想法,这真的很酷,我很惊讶我以前从未见过它!
    • 如果您的位图非常稀疏,您可以用其他形式来表示它,例如平衡树,其中迭代算法非常有名。
    • 如果您的位图稀疏但区域密集(这听起来很奇怪,但我遇到的情况正是这种情况),请使用小型(32 位或 64 位)位图的平衡树并使用树和单词位的组合迭代算法。
    • 为避免显式树的内存开销,请使用隐式树,就像在规范堆排序算法中一样。在你的 bitset 准备好并且不会被变异之后,在它上面构建一个“金字塔”,其中 level(N+1)[i] = level(N)[2*i] |级别(N)[2*i+1]。这将允许您快速跳过 bitset 中无人居住的区域,并且迭代将以类似于迭代常规二叉树的方式完成。你不妨建立一个居住金字塔,从字节等开始:这一切都取决于你的比特集有多稀疏。
    • 有一些众所周知的位技巧可用于查找字中前导零的数量;例如,参见 java 标准库的 code
    • 通过使用被动迭代器而不是主动迭代器 t.i.,您可能会获得很多性能。代替 begin() 和 operator++(),为您的位集提供一个 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++;
        }
    }
    

    第二个代码 sn-p 仅比第一个代码快 1.66 倍(~1.5s vs ~2.5s)。我认为更稀疏的位数组甚至可能使第一个代码优于第二个代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多