迭代std :: bitset中真实位的有效方法?

Posted

技术标签:

【中文标题】迭代std :: bitset中真实位的有效方法?【英文标题】:Efficient way of iterating over true bits in std::bitset? 【发布时间】:2011-06-10 04:45:24 【问题描述】:

有没有一种方法可以迭代(可能很大)std::bitset,它在 设置为 true 的位数中线性?我想避免检查位集中的每个位置。迭代应该连续返回每个设置为 true 的位的索引。

【问题讨论】:

【参考方案1】:

标准位向量不支持对真实位进行有效迭代 - 运行时间始终为 O(n),其中 n 是总位数,与 k 无关。但是,有专门的数据结构,如 van Emde Boas trees 和 y-fast tries,支持在时间 O(k lg lg n) 内对比特进行迭代,其中 n 是比特数,k 是真实比特数。

【讨论】:

【参考方案2】:

为了使其成为线性,您需要一个链表/数组/索引集设置为 true。保留这样的二级索引不是 std::bitset 要求的性能/存储权衡的一部分,并且如果没有您的特定要求,它会使每个人都处于不利地位,因此实现无法提供这一点。你可以考虑自己用这样的容器来补充你的 bitset,或者使用 boost 的多索引容器库。

【讨论】:

我明白了。不幸的是,单独存储索引不是一种选择。感谢您的见解。【参考方案3】:

您可以使用 u64 累加器和 32 条目表一次最多检查 32 位


u32 kTable[]

0x01, 0x03, 0x07, 0x0F ..., 0xFFFFFFFF
;

只需将 32 位读入 u64 累加器并根据偏移量将其向下移动,然后对照表检查您的位。您可以以二进制方式执行此操作,以使比较次数最多为 5。对于时尚非“线性”的数据,这将变慢。然后这成为日志时间。

【讨论】:

有趣。你能多说一下如何使用这样的表吗? O(N/32) 仍然是 O(N) - 这在总位数中又是线性的。 kTable 已排序,因此您可以搜索您的位。这使得日志时间【参考方案4】:

只有两个选项在总位数上比 O(N) 好得多:

    使用特定架构中可用的特殊位扫描指令,例如 BSF in x86。 有 O(log2(N)) 算法可用于查找字中设置的最低位。当位集密集而不是稀疏时,这当然不能很好地扩展。复活了我一些模糊的记忆,我在FXT library找到了出处,详情可以在FXT book (pdf)找到,在第1.3.2节中。

【讨论】:

【参考方案5】:

有时人们使用run-length encoding 来处理类似的事情。如果将传入的位集编码为一个运行长度数组,那么最终的运行次数不会超过设置位和清除位之间的转换次数,最多为2*k。此外,在许多应用程序中,转换次数远少于k,因此除了线性最坏情况之外,您还可以获得出色的平均时间性能。

此外,添加一个数据结构很简单,它可以让您有效地搜索诸如“数组中以nth 位置开始的下一个设置位”:只需构建一个运行长度的scan。

【讨论】:

【参考方案6】:

遍历整个位集并简单地检查值并存储索引,如果为真,则为线性。您可以使用查找表加快速度。请参阅此代码:

http://xiangqi-engine.cvs.sourceforge.net/viewvc/xiangqi-engine/tsito2/src/Utility.cpp?revision=1.5&view=markup

【讨论】:

问题的重点是扫描整个位集不一定与所设置的位数成线性关系。例如,如果已知位集的数量为 ~ ln N,其中 N 是集的大小,则扫描仍将花费 O(N) 而不是 O(ln N)。 Eddie,真实位数不是线性的。请考虑编辑您的答案或将其删除。

以上是关于迭代std :: bitset中真实位的有效方法?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 std::bitset 不带有迭代器?

有没有合理的方法从bitset中提取最低有效数字?

理论: STL: bitset

为啥 BitSet 不可迭代?

C++中标志位的几种实现方法

在 unordered_multimap 中准确地迭代每个键一次的有效方法