在C中,是否有任何优化的方法来检索BitPositions列表而不解析每个位。
考虑以下示例
int bitmap[4];
因此,有4 * 32位位置。值等于
bitmap = { 0x1, 0x0, 0x0, 0x0010001 }
我希望检索每个位集的位置,而不是从0到4 * 32位置进行解析。
答案 0 :(得分:0)
首先,人们不能真正在C中使用 int
作为位图,因为向左移位到符号位的行具有未定义的行为,C不保证表示是两个补码,或者int中有32位;据说避免这些陷阱的最简单方法是使用uint32_t
来自<stdint.h>
。因此
#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
为0的任何bitmap[index]
,因为它不包含任何位;同样,在每个索引中,你可以通过将uint32_t中的位从位图右移位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)之外没有太多加速,但你仍然必须使用一些。
答案 1 :(得分:0)
在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位整数)。
注意:如果额外的内存使用对您来说不是问题,您可以构建一个64位的16位表项,并将结构数减少一半。
答案 2 :(得分:0)
关于这个问题,你可以看到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 是设置位数。