【问题标题】:Get list of bits set in BitMap获取 BitMap 中设置的位列表
【发布时间】:2017-02-19 07:30:50
【问题描述】:

在 C 语言中,是否有任何优化的方法可以在不解析每个位的情况下检索 BitPositions 集的列表。

考虑下面的例子

int bitmap[4];

所以,有 4 * 32 位位置..值如下

bitmap = { 0x1, 0x0, 0x0, 0x0010001 }

我想检索每个位集的位置,而不是从 0 到 4 * 32 个位置进行解析。

【问题讨论】:

  • 您确定需要列表吗?当您需要时,在bitmap 中进行测试可能比在列表中搜索位号更快...
  • @Dmitri 其实我想知道位位置集的列表。

标签: c bitmap bit-manipulation


【解决方案1】:

首先,在 C 中不能真正将 int 用于位图,因为向左移动一位到符号位具有未定义的行为,C 不保证表示是二进制的补码,或者 int 中有 32 位;据说避免这些陷阱的最简单方法是改用来自<stdint.h> 的uint32_t。因此

#include <stdint.h>
uint32_t bitmap[4];

因此,请考虑将这些位从索引 0 ... 3 编号为 0 ... 127;并且在索引 0 ... 31 内;因此,您可以使用以下公式获取数组的索引和该值中的位数:

int bit_number = // a value from 0 ... 127
int index = value >> 32; // shift right by number of bits in each index
int bit_in_value = value & 31; // take modulo 32 to get the bit in value

现在您可以通过以下方式索引整数:

bitmap[index];

所需值的位掩码是

uint32_t mask = (uint32_t)1 << bit_in_value;

所以你可以通过做检查该位是否设置

bit_is_set = !!(bitmap[index] & mask);

现在为了加快速度,您可以跳过任何 index 的 bitmap[index] 为 0,因为它不包含任何位集;同样,在每个索引中,您可以通过将 uint32_t 中的位从位图 right 移动 1 并用 1 屏蔽来加快速度;并在 uint32_t 变为 0 时打破循环:

for (int index = 0; index <= 3; index ++) {
     uint32_t entry = bitmap[index];
     if (! entry) {
         continue;
     }

     int bit_number = 32 * index;
     while (entry) {
         if (entry & 1) {
             printf("bit number %d is set\n", bit_number);
         }
         entry >>= 1;
         bit_number ++;
     }   
}

除了查找表或使用编译器内在函数(例如this to set which is the lowest bit set)之外,没有什么可以加快速度的,但无论如何您仍然必须使用一些。

【讨论】:

  • 谢谢回复....这也是一种贪婪的方式...优化迭代所有位。考虑跟随位图......在这种情况下,复杂性与遍历所有位相同。对?位图[4] = { 0x80000001, 0x80000001, 0x80000001, 0x80000001}。
【解决方案2】:

可以通过使用查找表来实现在 O(k) 中运行的最佳解决方案,其中 k = 整个列表中设置的总位数。例如,您可以使用包含 256 个条目的表来描述该字节中每个设置位的位位置。索引将是字节的实际值。

对于每个条目,您可以使用以下结构。

struct
{
   int numberOfSetBits;
   char* list; // use malloc and alloocate the list according to numberOfSetBits
}

然后您可以遍历每个结构的列表成员,并且迭代次数 = 该字节的设置位数。对于 32 位整数,您必须遍历其中的 4 个结构,每个字节一个。要确定需要检查的条目,请使用位图并移动 8 位。请注意,位位置与该字节相关,因此您可能需要添加偏移量或 24、16 或 8,具体取决于您正在迭代的字节(假设为 32 位整数)。

注意:如果额外的内存使用对您来说不是问题,您可以构建一个 64K 的 16 位条目表,您可以将结构的数量减少一半。

【讨论】:

  • 一个问题是,64k 表真的更快吗 - 因为 OP 需要获取 all 位位置;然而,需要进行计算才能将它们中的每一个调整到适当的位位置-
  • @AnttiHaapala - 有一点好处,因为每个整数只有一个(16 位)移位,而 3(b 位)移位(24、16 和 8)具有8 位表。我很小心,但是不要写复杂性降低了。两种情况下的复杂度 O(k) 其中 k = 设置的位数,这是最优的。
【解决方案3】:

与这个问题相关的,可以看What is the fastest way to return the positions of all set bits in a 64-bit integer?

一个简单的解决方案,但可能不是最快的,具体取决于 log 和 pow 函数的时间:

#include<math.h>
#include<stdio.h>

void getSetBits(unsigned int num, int offset){

    int bit;
    while(num){
        bit = log2(num);
        num -= pow(2, bit);

        printf("%i\n", offset + bit); // use bit number
    }
}

int main(){
    int i, bitmap[4] = {0x1, 0x0, 0x0, 0x0010001};
    for(i = 0; i < 4; i++)
        getSetBits(bitmap[i], i * 32);
}

复杂度 O(D) | D 是设置的位数。

【讨论】:

    猜你喜欢
    • 2011-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多