位图算法
需求:有很多不重复的整数, 其中最大值不超过 40 亿, 最小值是 0.
要求判断某个指定的整数, 是否在这个集合中
思路:一个字节可以放8个数,申请一个可以放下(40亿/8)字节的内存,使用位图算法,用空间换时间
#include <iostream>
#include <stdio.h>
using namespace std;
/*
有很多不重复的整数, 其中最大值不超过 40 亿, 最小值是 0.
要求判断某个指定的整数, 是否在这个集合中
*/
#define MAX_NUMBER 4000000000 //最大值 40亿
// 装载数据集合
void init(char* data, int len)
{
// 计算len个字节能放多少个数
unsigned int num = len * 8;
// 这里我们假设能被3整除的数都在集合中
for (unsigned int i = 0; i < num; i++)
{
if (i % 3 == 0)
{
// 定位到所在字节
char* p = data + i / 8;
// 定位到所在字节的具体位数,并将该位设置为1(或操作)
int binary = 1 << (i % 8); // 例如: 1 << 4 得到 0001 0000
*p = *p | binary;
}
}
}
bool check(char* data, int len, unsigned int value)
{
// 定位到所在字节
char* p = data + value / 8;
// 定位到所在字节的所在二进制位,并判断该位是否为1(与操作)
int binary = 1 << (value % 8);
bool ret = *p & binary;
return ret;
}
int main()
{
// 申请内存
unsigned int len = MAX_NUMBER / 8 + 1; //加1是因为如果前面相除的数是0,必须要占一个字节
char* data = (char*)malloc(len);
if (!data)
{
cout << "data is NULL" << endl;
return 0;
}
memset(data, 0, len); // 清零
// 装载数据集合
cout << "正在加载数据,请稍后..." << endl;
init(data, len);
// 用户输入数据并判断是否在数据集合中
while (1)
{
unsigned int input = 0;
cout << "请输入需要判断的数据:[输入-1退出]: ";
cin >> input;
if (input == -1)
{
break;
}
if (check(data, len, input))
{
cout << input << "在数据集合中" << endl;
}
else
{
cout << input << "不在数据集合中" << endl;
}
}
return 0;
}