迭代一个位序列并找到每个设置位

时间:2013-05-09 23:49:52

标签: algorithm bit-manipulation

我的问题或多或少是标题中的内容;我想知道是否有一种快速的方法来查找一系列位并查找已设置的每一位。

更详细的信息:

我目前正在开发一个代表一组对象的数据结构。为了支持我需要的一些操作,结构必须能够在内部执行非常快速的子集交集。我提出的解决方案是让结构的超集的每个子集由“位数组”表示,其中每个位映射到包含超集数据的数组中的索引。示例:如果在子集中设置了位#1,则超集的数组中索引1处的元素将出现在子集中。

每个子集由一个足够大的ulong数组组成,有足够的位来表示整个超集(如果超集包含256个元素,则数组的大小必须为256/64 = 4)。为了找到2个子集S1和S2的交集,我可以简单地遍历S1和S2的数组,并在每个索引处找到按位和在ulongs之间。

现在回到我的问题: 为了返回子集的数据,我必须迭代子集的“位数组”中的所有位并找到设置的位。这就是我如何做到这一点:

 /// <summary>
 /// Gets an enumerator that enables enumeration over the strings in the subset.
 /// </summary>
 /// <returns> An enumerator. </returns>
 public IEnumerator<string> GetEnumerator()
 {
     int bitArrayChunkIndex = 0; 
     int bitArrayChunkOffset = 0; 
     int bitArrayChunkCount = this.bitArray.Length; 

     while(bitArrayChunkIndex < bitArrayChunkCount)
     {
         ulong bitChunk = bitArray[bitArrayChunkIndex];

         // RELEVANT PART

         if (bitChunk != 0)
         {
              int bit = 0;
              while (bit < BIT_ARRAY_CHUNK_SIZE  /* 64 */)
              {
                   if(bitChunk.BitIsSet(bit))
                        yield return supersetData[bitArrayChunkOffset + bit];
                   bit++;
              }
         }
         bitArrayChunkIndex++;
         bitArrayChunkOffset += BIT_ARRAY_CHUNK_SIZE;

         // END OF RELEVANT PART
     }
 }

有没有明显的优化方法?有没有什么能够让它快速完成?谢谢!

2 个答案:

答案 0 :(得分:1)

在INTEL 386+上,您可以使用机器指令BitSearchFirst。 以下 - gcc样本。这对于64位进程来说有点棘手, 但无论如何都要快速有效。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(int argc, char **argv) {
  uint64_t val;
  sscanf(argv[1], "%llx", &val);
  printf("val=0x%llx\n", val);
  uint32_t result;
  if((uint32_t)val) { // first bit is inside lowest 32
    asm("bsfl %1,%0" : "=r"(result) : "r"(val));
  } else {             // first bit is outside lowest 32
    asm("bsfl %1,%0" : "=r"(result) : "r"(val >> 32));
    result += 32;
  }
  printf("val=%llu; result=%u\n", val, result);
  return 0;
}

另外,在使用x64架构时,您可以尝试使用bsfq指令,并删除“if / else”

答案 1 :(得分:0)

取16个整数的数组,用从0到15的整数设置的位数初始化(即0,1,1,2,1,2,2,3,1,2,2,3, 2,3,3,4)。现在取bitchunk%16,并在int数组中查找结果 - 这是块的前四位中的设置位数。右移四次,并重复整个操作十五次。

您可以使用256个整数和8位子块的数组来执行此操作。我不建议使用带有12位子块的4096个整数数组,这有点荒谬。

int[] lookup = new int[16] {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
int bitCount = 0;
for(int i = 0; i < 16; i++) {
    int firstFourBits = bitChunk % 16;
    bitCount += lookup[firstFourBits];
    bitChunk = butChunk >> 4;
}