位向量的位数组用作从位置到某个位值的映射。是的,它基本上与 Bool 数组相同,但典型的 Bool 实现是 1 到 4 个字节长,并且占用了太多空间。
我们可以通过使用单词数组和二进制掩码操作以及转移来存储和检索它们来更有效地存储相同数量的数据(使用更少的整体内存,更少的内存访问,更少的缓存未命中,更少的内存页面交换)。访问各个位的代码仍然非常简单。
C 语言中还内置了一些位字段支持(你写的东西就像int i:1;
说“只消耗一位”),但它不适用于数组,并且你对整体结果的控制较少(实现细节取决于编译器和对齐问题)。
以下是回答您的“搜索缺失号码”问题的一种可能方式。我将 int 大小固定为 32 位以保持简单,但可以使用 sizeof(int) 编写它以使其可移植。并且(取决于编译器和目标处理器)代码只能使用>> 5
代替/ 32
和& 31
代替来更快% 32
,但这只是为了给出想法。
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
int main(){
/* put all numbers from 1 to 1000000 in a file, except 765 and 777777 */
{
printf("writing test file\n");
int x = 0;
FILE * f = fopen("testfile.txt", "w");
for (x=0; x < 1000000; ++x){
if (x == 765 || x == 777760 || x == 777791){
continue;
}
fprintf(f, "%d\n", x);
}
fprintf(f, "%d\n", 57768); /* this one is a duplicate */
fclose(f);
}
uint32_t bitarray[1000000 / 32];
/* read file containing integers in the range [1,1000000] */
/* any non number is considered as separator */
/* the goal is to find missing numbers */
printf("Reading test file\n");
{
unsigned int x = 0;
FILE * f = fopen("testfile.txt", "r");
while (1 == fscanf(f, " %u",&x)){
bitarray[x / 32] |= 1 << (x % 32);
}
fclose(f);
}
/* find missing number in bitarray */
{
int x = 0;
for (x=0; x < (1000000 / 32) ; ++x){
int n = bitarray[x];
if (n != (uint32_t)-1){
printf("Missing number(s) between %d and %d [%x]\n",
x * 32, (x+1) * 32, bitarray[x]);
int b;
for (b = 0 ; b < 32 ; ++b){
if (0 == (n & (1 << b))){
printf("missing number is %d\n", x*32+b);
}
}
}
}
}
}