二进制数可方便进行集合的表示与运算
一、如何表示集合
二进制数的每一位代表了此处的开关状态,以此来表示集合中元素的有无。
一些特殊集合的表示:全集 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)。