C++实现bitmap去重统计

Bitmap(位图)是一种使用位(bit)来表示元素是否存在的数据结构,特别适合大规模整数去重统计,内存占用极低。

  

## Bitmap类实现

  

```cpp

#include

#include

#include

  

class Bitmap {

private:

    std::vector bits;

    size_t numBits;

public:

    // 构造函数,创建能容纳maxNum个数的bitmap

    Bitmap(size_t maxNum) : numBits(maxNum) {

        // 每个字节8位,向上取整计算需要的字节数

        bits.resize((maxNum + 7) / 8, 0);

    }

    // 设置某个位为1

    void set(size_t pos) {

        if (pos >= numBits) return;

        bits[pos / 8] |= (1 << (pos % 8));

    }

    // 检查某个位是否为1

    bool test(size_t pos) const {

        if (pos >= numBits) return false;

        return (bits[pos / 8] & (1 << (pos % 8))) != 0;

    }

    // 清除某个位(设为0)

    void clear(size_t pos) {

        if (pos >= numBits) return;

        bits[pos / 8] &= ~(1 << (pos % 8));

    }

    // 统计设置为1的位数(不同元素的数量)

    size_t count() const {

        size_t sum = 0;

        for (size_t i = 0; i < numBits; ++i) {

            if (test(i)) {

                sum++;

            }

        }

        return sum;

    }

    // 更高效的统计1的位数的方法

    size_t countEfficient() const {

        static const unsigned char bitCounts[256] = {

            0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,

            1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,

            1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,

            2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

            1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,

            2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

            2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

            3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

            1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,

            2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

            2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

            3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

            2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

            3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

            3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

            4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8

        };

        size_t sum = 0;

        // 计算完整字节

        size_t completeBytes = numBits / 8;

        for (size_t i = 0; i < completeBytes; ++i) {

            sum += bitCounts[bits[i]];

        }

        // 处理剩余不足一个字节的位

        size_t remainingBits = numBits % 8;

        if (remainingBits > 0) {

            unsigned char mask = (1 << remainingBits) - 1;

            sum += bitCounts[bits[completeBytes] & mask];

        }

        return sum;

    }

};

```

  

## 使用示例:整数去重统计

  

```cpp

#include

#include

#include

#include

#include

  

int main() {

    const size_t MAX_VALUE = 10000000;  // 可能出现的最大整数值

    const size_t DATA_SIZE = 5000000;   // 测试数据量

    // 生成随机数据

    std::vector data;

    data.reserve(DATA_SIZE);

    std::srand(std::time(nullptr));

    for (size_t i = 0; i < DATA_SIZE; ++i) {

        data.push_back(std::rand() % MAX_VALUE);

    }

    // 方法1:使用Bitmap进行去重统计

    clock_t start = clock();

    Bitmap bitmap(MAX_VALUE);

    for (int num : data) {

        bitmap.set(num);

    }

    size_t uniqueCount = bitmap.countEfficient();

    clock_t end = clock();

    std::cout << "Bitmap统计结果: 共有" << uniqueCount << "个不同的整数" << std::endl;

    std::cout << "Bitmap耗时: " << double(end - start) / CLOCKS_PER_SEC << "秒" << std::endl;

    // 方法2:使用unordered_set进行去重统计(对比)

    start = clock();

    std::unordered_set numSet;

    for (int num : data) {

        numSet.insert(num);

    }

    end = clock();

    std::cout << "Set统计结果: 共有" << numSet.size() << "个不同的整数" << std::endl;

    std::cout << "Set耗时: " << double(end - start) / CLOCKS_PER_SEC << "秒" << std::endl;

    return 0;

}

```

  

## Bitmap优势

  

1. **空间效率高**:每个整数只占用1个bit位,比如1000万个不同整数,只需约1.2MB内存

2. **去重自动完成**:同一个整数多次set操作,最终在bitmap中只占一个位

3. **统计高效**:对于有限范围的整数,统计速度快,内存占用少

  

## 使用场景

  

1. 大规模整数去重统计(如统计网站UV)

2. 布隆过滤器的底层实现

3. 需要节省内存的场景下进行集合运算

  

## 局限性

  

1. 只适用于非负整数

2. 需要预先知道数据的最大值

3. 不保存原始数据,只记录数据是否存在

  

如需处理有符号整数或更复杂的数据类型,需要进行适当的映射或扩展实现。

你可能感兴趣的:(编程,c++,开发语言)