位图算法

需求:有很多不重复的整数, 其中最大值不超过 40 亿, 最小值是 0.
要求判断某个指定的整数, 是否在这个集合中

思路:一个字节可以放8个数,申请一个可以放下(40亿/8)字节的内存,使用位图算法,用空间换时间
image

#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;
}

image

posted @ 2022-05-03 13:46  荒年、  阅读(48)  评论(0编辑  收藏  举报