1. & Bitwise AND
(1) Introduction
& - 按位与
int a = 5,b = -6;
a & b - 二者需要使用补码来进行运算
0000 0000 0000 0000 0000 0000 0000 0101 - 5的补码
1111 1111 1111 1111 1111 1111 1111 1010 - -6的补码
0000 0000 0000 0000 0000 0000 0000 0000 - 5 & -6 的结果
& - 在一一对应的二进制位上,只有同时为1的二进制位运算的结果才是1 反之其他皆为0
(2), application
例如:
int a = 21 ;
0000 0000 0000 0000 0000 0000 0001 0101 - 21的补码
↑
第五的位数
现在,需要我们判断 21 的二进制位数 的第五个位数是1还是0
此时,若要解决该问题,我们可以利用 & 的性质解决问题
首先我们先将第五位数移到最右边,我们使用 >> 操作符 得到一串新的二进制数位
0000 0000 0000 0000 0000 0000 0000 0001 - a>>4
随后使用 (a>>4)&1 进行运算,最后进行对比
0000 0000 0000 0000 0000 0000 0000 0001 - 1的补码
0000 0000 0000 0000 0000 0000 0000 0001 - a>>4
0000 0000 0000 0000 0000 0000 0000 0001 - (a>>4)&1的结果
通过 & 的特性,我们得知了21的二进制位数的第五个位数是1
Second, | bitwise or
介绍:
| 按位或
int a = 5, b = -6;
a | b -二者需要使用补码进行运算
0000 0000 0000 0000 0000 0000 0000 0101 - 5的补码
1111 1111 1111 1111 1111 1111 1111 1010 - -6的补码
1111 1111 1111 1111 1111 1111 1111 1111 - 5 | -6的结果
| - 在一一对应的二进制位上,只要有1时就为1,只有同时为0时才能为0
(2), application
例如:
int a = 13;
// 0000 0000 0000 0000 0000 0000 0000 1101 - 13的补码
↑
要求将13的二进制位数中的第五位改成1
// 现在,要求将13的二进制位数中的第五位改成 1
// 对于此问题,我们可以使用 | 的性质解决问题
// 首先,我们先展示出 1 的二进制位数
// 0000 0000 0000 0000 0000 0000 0000 0001 - 1的补码
// 其次,我们使用 1 << 4 将1的二进制位数中唯一的1进行移动到二进制数位的第5位
// 随后,在使用 | 解决问题
// 0000 0000 0000 0000 0000 0000 0000 1101 - 13的补码
// 0000 0000 0000 0000 0000 0000 0001 0000 - 1<<4的结果
// 通过 | 的性质,我们可以得到
// 0000 0000 0000 0000 0000 0000 0001 1101
3. ^ Bitwise XOR
(1) Introduction
^ - 按位异或
int a = 5,b = -6;
a ^ b - 二者需要使用补码来进行运算
0000 0000 0000 0000 0000 0000 0000 0101 - 5的补码
1111 1111 1111 1111 1111 1111 1111 1010 - -6的补码
1111 1111 1111 1111 1111 1111 1111 1111 - 5 ^ -6 的结果
^ - 在一一对应的二进制位上,相同的位数为0,不相同的位数为1
(2), application
例如:
应用一:
int a = 3 , b = 5;
求不允许创建临时变量,使用按位异或操作符,交换两个整数的内容
首先,我们要知道 ^ 有一个特点,那就是 a ^ a = 0 以及 a ^ 0 = a
所以题目的要求可以使用以下代码解决:
a = a ^ b; - a = 3^5
b = a ^ b; - b = a ^ b ^ b = 3 ^ 5 ^ 5 = 3 ^ 0 = 3 - b = 3
a = a ^ b; - a = a ^ b = 3 ^ 5 ^ 3 = 3 ^ 3 ^ 5 = 0 ^ 5 = 5 - a = 5
通过以上的运算,我们又得知 ^ 和数学符号 乘号× 一样 具有交换律的特点
应用二:
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。请实现函数:
int singleNumber(int nums[], int numsSize),找出那个只出现一次的元素。
int singleNumber(int nums[], int numsSize)
{
int k = 0;
int i = 0;
for (i = 0; i < numsSize; i++)
{
k = k ^ nums[i];
//0^4^1^2^1^2 = 0^4^0^0 = 0^4 = 4 利用了^的特性,也就是 a ^ a = 0 和 0 ^ a = a
}
return k;
}
int main()
{
int nums[] = { 4,1,2,1,2 };
int numsSize = sizeof(nums) / sizeof(nums[0]);
int ret = singleNumber(nums,numsSize);
printf("%d",ret);
return 0;
}
注意,这种异或操作是有局限性:
1.只能作用于整数交换
2.代码的可读性差
3.代码执行的效率也是低于使用第3个变量的方法
Four, ~ bitwise inversion
(1) Introduction
~ - 按位取反
int a = 0;
~ a - 需要使用补码来进行运算
0000 0000 0000 0000 0000 0000 0000 0000 - 0的补码
1111 1111 1111 1111 1111 1111 1111 1111 - ~0 的结果
~ - 在二进制数位上是0的变成1,是1的变成0,且包括了符号位
(2), application
例如:
int a = 29;
// 0000 0000 0000 0000 0000 0000 0001 1101 - 29的补码
↑
要求第五位数改成0
// 现在,要求将29的二进制位数中的第五位改成 0
// 对于此问题,我们可以使用 ~ 的性质解决问题
// 首先,我们先展示出 1 的二进制位数
// 0000 0000 0000 0000 0000 0000 0000 0001 - 1的补码
// 其次,我们使用 1 << 4 将1的二进制位数中唯一的1进行移动到二进制数位的第5位
// 0000 0000 0000 0000 0000 0000 0001 0000 - 1<<4的结果
// 随后,在使用 ~ 进行取反
// 1111 1111 1111 1111 1111 1111 1110 1111 - ~(1<<4)的结果
// 再之后,使用 & 的性质解决问题
// 0000 0000 0000 0000 0000 0000 0000 1101 - a & ~(1<<4)的结果