[笔记]利用二进制数进行集合运算

二进制数可方便进行集合的表示与运算

一、如何表示集合

二进制数的每一位代表了此处的开关状态,以此来表示集合中元素的有无。
一些特殊集合的表示:全集 2^n-1, 空集 0 。

1.如何向集合中插入元素

若要插入第 n 号元素,只需向代表集合的二进制数加上 2^n 即可。

2.如何读取集合中元素的有无

只需将二进制数按位与 1<<n。结果若为 1,即有元素;为 0,即无元素。
遍历集合中的各元素只需每位按位与。


二、位运算与集合运算

利用位运算可方便快速的进行集合运算。

A B A&B A|B A^B
二进制 10110 01100 00100 11110 11010
集合 {1, 2, 4} {2, 3} {2} {1, 2, 3, 4} {1, 3, 4}
操作 取交集 取并集 对称差

利用位运算还可简单实现取子集。


三、示例

#include <cstdio>
const int n=5;
void output(int set){
    for (int i=0; i<5; i++)
	if (set & (1<<i)) printf("%d ", i+1);
    printf("
");
}

int main(void){
    int A=22, B=12, U=(1<<n)-1;//A{2, 3, 5} B{3, 4}
    
    printf("集合A: ");
    output(A);
    printf("集合B: ");
    output(B);
    printf("A&B: ");
    output(A&B);
    printf("A|B: ");
    output(A|B);
    printf("A^B: ");
    output(A^B);
    printf("A的补集: ");
    output(U^A);
    printf("
A的所有子集: 
");
    //取子集操作
    for (int s=(A-1)&A; s!=0; s=(s-1)&A) output(s);
    printf("全集的所有子集:
");
    for (int i=1; i<U; i++) output(i);

    return 0;
}

输出结果:

集合A: 2 3 5 
集合B: 3 4 
A&B: 3 
A|B: 2 3 4 5 
A^B: 2 4 5 
A的补集: 1 4 

A的所有子集: 
2 3 5 
3 5 
2 5 
5 
2 3 
3 
2 
全集的所有子集:
1 
2 
1 2 
3 
1 3 
2 3 
1 2 3 
4 
1 4 
2 4 
1 2 4 
3 4 
1 3 4 
2 3 4 
1 2 3 4 
5 
1 5 
2 5 
1 2 5 
3 5 
1 3 5 
2 3 5 
1 2 3 5 
4 5 
1 4 5 
2 4 5 
1 2 4 5 
3 4 5 
1 3 4 5 
2 3 4 5 
1 2 3 4 5 

四、二进制表示集合的缺点及解决方法

1.数据范围小

可以知道最大范围的数据类型为64位的 long long, 一共可以表示64个元素。那么如果总元素大于64呢?

解决方法

利用数组可以简单解决取交集、并集、对称差,也可解决取子集问题。
取交集、并集、对称差 可以用数组中每一数进行位运算;
取子集 可每次先按数组中最高一位数取子集,后找低一位数的子集(类似dfs)。

原文地址:https://www.cnblogs.com/tanglizi/p/7707759.html