之前我是写过一个位运算的博客的:
但是我发现其中涉及的内容远远不够,所以现在我们再来重新写一个博客,总结位运算算法
相比于之前的内容,我找到了一张更全的位运算计算总结,这里给大家参考一下!!!
除了这些我们再来补充一些其余的:
判断两数符号是否相同:
int x,y;
bool f=((x^y)<0);
判断一个数是否是2 的幂次:
int x;
bool f=(x^(x-1))==0;
计算较小值/计算较大值:(useless)
int x,y;
//小值:
int min=y^((x^y)&-(x<y));
int max=x^((x^y)&-(x<y));
得到右数第一个1和后面的 0 构成的数:
int x;
int ret=x&(-x);
//或者
int ret2=x-(x&(x-1));
计算一个数的二进制有几个 1:
int x,count;
while(x)
{
x=&(x-1);
count++;
}
交换两个数:
int a,b;
a^=b;
b^=a;
a^=b;
位运算还经常被用于状态压缩时的集合枚举。
比如现在有 n件物品,编号从1到n,我们可以用一个n位二进制数来表示每个物品取或不取的状态,二进制数从右往左数第 k位的 01 状态表示编号为k的物品取了还是没有取(1 表示取了,0 表示没有取)。
在枚举集合进行运算的过程当中,我们经常遇到要枚举当前集合的子集或超集的情况
下面我们给出子集和超集的概念:
子集:对于两个集合A与B,如果集合A的任何一个元素都是集合B的元素,我们就说集合A包含于集合B,或集合B包含集合A,也说集合A是集合B的子集
超集:如果一个集合S2中的每一个元素都在集合S1中,且集合S1中可能包含S2中没有的元素,则集合S1就是S2的一个超集
下面我们来学习如何枚举一个二进制所有的子集:
int n;//n指的是二进制位数
for (int i = 1; i < (1 << n); i++)
{
for (int j = i; j; j = (j - 1) & i)
{
//枚举所有子集
}
}
枚举一个二进制所有的超集:
int n;//n指的是二进制位数
for (int i = 1; i < (1 << n); i++)
{
for (int j = i; j < (1 << n); j = (j + 1) | i)
{
//枚举所有超集
}
}
时间复杂度都是O(3的n次方)
感谢大家的支持!!!