【问题标题】:Fastest way to get consecutive index of each set bit?获取每个设置位的连续索引的最快方法?
【发布时间】:2015-05-25 06:25:11
【问题描述】:

假设我有一个整数,它的二进制表示如下:

1001 1011 0111 0001 0010 1100 1000 1111

我正在寻找一种方法来获取每个设置位的连续索引。我正在将数组元素从一个数组移动到另一个数组。元素个数就是个数。

在本例中,第一个数组的前 4 个元素将移动到第二个数组的前 4 个索引(从右侧开始:LSB)。

但是,在那之后,第一个数组的第五个元素将移动到第二个数组的第 8 个索引,因为有 3 个零的间隙(所以第 8 个索引 = 索引 7)。

希望您现在可以看到模式。我想过可能转换为字符串并执行循环,但这似乎相当慢。我也可以在循环中使用一些像这样的位操作:

x & (x-1) 清除下一个设置位

(int)Math.Log((x & ~(x - 1)), 2); 查找下一个设置位。

还有一个解决方案,就是保持一个运行的索引并保持与 1 并在每次迭代时移位 1。

但我不确定是否有更好的方法,或者我是否缺少更简单的方法。

【问题讨论】:

标签: c# arrays binary bit-manipulation


【解决方案1】:

我认为带有运行索引的简单循环应该可以正常工作。对 Math.Log 的调用肯定不会更快,De Bruijn 也不会位黑客操作。如果可以在 c# 中进行汇编/内在函数来查找前导/尾随 0,则可能会做得更好。

现在,我建议使用简单的循环,当mask 变为 0 时有一个终止标准,如下所示:

static void CopyByMask<T>(UInt32 mask, T[] srcArray, T[] destArray)
{
    // Note: assumes arrays are appropriately sized.
    var srcPos = 0;
    for (var destPos = 0; mask != 0; destPos++)
    {
        if ((mask & 1) == 1)
            destArray[destPos] = srcArray[srcPos++];
        mask >>= 1;
    }
}

【讨论】:

  • 我认为 (mask &amp; 1) == 1mask &gt;&gt;= 1 正是 OP 所缺少的。没有比这更好的方法了。
  • 不错,这看起来是最好的解决方案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-04
  • 1970-01-01
相关资源
最近更新 更多