一,位运算是什么?
把两个数化作二进制,来进行&,^等运算。
例如对于异或运算^。
a=83,b=161。
将他们化为二进制:
a=0101 0011
b=0111 0001。
异或运算就是不一样为1,一样为0.
所以结果为0010 0010。
异或运算可以看成不进位的加法运算。因此根据加法交换律结合律。异或运算也有交换律结合律。
注意:
1,a^0=a
2,a^a=0
还有一个会用到的结论,任何数与0异或运算,结果不变
这个和加法运算中加一个0和乘法运算当中乘一个1,结果不变,有异曲同工之妙。
异或运算小聪明:
实现两个数交换的代码。
常规:
#include<stdio.h>
int main()
{
int a, b;
a = 12;
b = 11;
int c = 0;
c = a;
a = b;
b = c;
printf("%d,%d", a, b);
return;
}
只用两个变量:
#include<stdio.h>
int main()
{
int a, b;
a = 12;
b = 11;
a = a + b;
b = a - b;
a = a - b;
printf("%d,%d", a, b);
return;
}
异或运算:
#include<stdio.h>
int main()
{
int a, b;
a = 12;
b = 11;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("%d,%d", a, b);
return;
}
解释一下:
对于第一次异或运算
a=a^b,b=b
对于第二次异或运算
a=a^b,b=a^b^b=a
第三次:
a=a^b^a=a^a^b=b,b=a
二,两个小题目
例1
题目:对于一组数,只有一个数是奇数个相同,其他数都是偶数个相同,找出奇数个相同的数。
解释:因为对于两个相同的数做异或运算,结果为0,又由于,在异或运算当中多异或一个0,对结果没有影响
#include<stdio.h>
int main()
{
int arr[20] = {1,1,1,1,
2,2,3,3,4,4,4,4,4,4,5};
int a = 0;
for (int i = 0;
i < sizeof(arr) / sizeof(arr[0]); i++)
{
a = a ^ arr[i];
}
printf("%d", a);
return;
}
例2
题目:对于一组数,如果有两个数都是奇数个相同,其他数都是偶数个相同,找出两个奇数个相同的数。
1.首先将所有数异或运算,得到的就是那两个找不到女朋友的数做异或运算的结果
2.上一步得到的结果 异或运算上 找不到女朋友的数的 任意一个,都可以找到剩下的那个
3.因此有一个办法就是分两组。
以这个为标准分组
rightone = a & (~a + 1);
这个是一个数与上其补码,可以找到二进制数右边第一个为1的数
- 接着随便异或运算一组就可以得出另外一个数
#include<stdio.h>
int main()
{
int arr[30] = {1,1,1,1,
2,2,3,3,4,4,4,4,4,4,5,7,7,7};
int a = 0;
for (int i = 0;
i < sizeof(arr) / sizeof(arr[0]); i++)
{
a = a ^ arr[i];
}
int rightone = 0;
rightone = a & (~a + 1);
int b = 0;
for (int i = 0;
i < sizeof(arr) / sizeof(arr[0]); i++)
{
if ((rightone & arr[i]) == 0)
{
b = b ^ arr[i];
}
}
printf("%d,%d",b, a ^ b);
return;
}