文章

位图

位图是一种数据结构,用位表示元素的存在与否,具有高效的空间和时间效率,常用于处理集合、计数和图像表示等应用。

位图

位图

  • 用 bit 组成的数组来存放值,用 bit 状态 1,0 代表存在不存在,取值和存值都用位运算。限制是必须为连续范围且不能过大。

  • 实现

1
2
3
4
5
6
7
8
9
10
11
// 初始化位图大小,只支持 0 ~ n - 1 所有数字的增删改查
void Bitset(int n);

void add(int num);

void remove(int num);

// 如果位图里没有 num,就加入;如果有就删除
void reverse(int nums);

bool contains(int num);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>

using namespace std;

vector<int> st;

// 初始化位图大小,只支持 0 ~ n - 1 共 n 个数字的增删改查
void Bitset(int n) {
    // a / b 的结果向上取整:(a + b - 1) / b,前提都是正数
    st.resize((n + 31) / 32);
}

// 加入位图
// 下标从 0 开始,num 在编号为 num / 32 的 32 位 int 中,下标为 num % 32
// 1 << (num % 32) 表示把 1 左移 (num % 32) 位
void add(int num) {
    st[num / 32] |= 1 << (num % 32);
}

// 删除
void remove(int num) {
    st[num / 32] &= ~(1 << (num % 32));
}

// 如果位图里没有 num,就加入;如果有就删除
void reverse(int num) {
    st[num / 32] ^= 1 << (num % 32);
}

// 是否包含
bool contains(int num) {
    return ((st[num / 32] >> (num % 32)) & 1) == 1;
}

int main() {
    int n = 1000;
    int testTimes = 10000;
    // 位图,范围 0~999
    Bitset(n);
    // 自带的 set 进行对比测试
    unordered_set<int> hashSet;

    srand(time(NULL));
    for (int i = 0; i < testTimes; ++i) {
        double decide = rand() / (double) (RAND_MAX);
        // 范围 0~999
        int number = rand() % (n - 1);
        if (decide < 0.333) {
            add(number);
            hashSet.emplace(number);
        } else if (decide < 0.666) {
            remove(number);
            hashSet.erase(number);
        } else {
            reverse(number);
            if (hashSet.find(number) == hashSet.end())
                hashSet.emplace(number);
            else
                hashSet.erase(number);
        }
    }

    bool flag = true;
    for (int i = 0; i < 1000; ++i) {
        if (contains(i) != (hashSet.find(i) != hashSet.end())) {
            flag = false;
            break;
        }
    }
    cout << boolalpha << flag;
}

2166. 设计位集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>

using namespace std;

class Bitset {
public:
    vector<int> st;
    int len;
    bool reversed = false;
    int oneCount = 0;
    int zeroCount;

    Bitset(int size) {
        len = size;
        zeroCount = size;
        st.resize((size + 31) / 32);
    }

    bool isOne(int idx) {
        return (st[idx / 32] & (1 << (idx % 32))) != 0;
//        return ((st[idx / 32] >> (idx % 32)) & 1) == 1;
    }

    void fix(int idx) {
        if ((!reversed && !isOne(idx))
            || reversed && isOne(idx)) {
            zeroCount--;
            oneCount++;
            reverse(idx);
        }
    }

    void unfix(int idx) {
        if ((!reversed && isOne(idx))
            || reversed && !isOne(idx)) {
            zeroCount++;
            oneCount--;
            reverse(idx);
        }
    }

/*    void fix(int idx) {
        int index = idx / 32;
        int bit = idx % 32;
        if (!reversed) {
            // 含义没反转,改成 1
            if (!isOne(idx)) {
                // idx 位置不是 1 的时候才要修改
                zeroCount--;
                oneCount++;
                st[index] |= (1 << bit);
            }
        } else {
            // 含义反转,改成 0
            if (isOne(idx)) {
                // idx 位置是 1 的时候才要修改
                zeroCount--;
                oneCount++;
//                st[index] &= ~(1 << bit);
                st[index] ^= (1 << bit);
            }
        }
    }*/

/*    void unfix(int idx) {
        int index = idx / 32;
        int bit = idx % 32;
        if (!reversed) {
            // 含义没反转,改成 0
            if (isOne(idx)) {
                zeroCount++;
                oneCount--;
//                st[index] &= ~(1 << bit);
                st[index] ^= (1 << bit);
            }
        } else {
            // 含义反转,改成 1
            if (!isOne(idx)) {
                zeroCount++;
                oneCount--;
                st[index] |= (1 << bit);
            }
        }
    }*/

    void reverse(int idx) {
        st[idx / 32] ^= (1 << (idx % 32));
    }

    // 数组中每个位其实没有反转,只是含义反转了
    void flip() {
        reversed = !reversed;
        swap(oneCount, zeroCount);
    }

    bool all() {
        return oneCount == len;
    }

    bool one() {
        return oneCount > 0;
    }

    int count() {
        return oneCount;
    }

    string toString() {
        string s;
        for (int i = 0; i < len; ++i) {
            char ch = '0';
            if ((reversed == false && isOne(i))
                || (reversed == true && !isOne(i)))
                ch = '1';
            s.append(1, ch);
        }
        return s;
    }
};
本文由作者按照 CC BY 4.0 进行授权