前言
此文章为学习记录,如有错误,请指正。
提示:以下是本篇文章正文内容,其中有些概念内容来源于网络
一、位运算的概念
现代计算机中所有的数据二进制的形式存储在设备中,非0即1。对二进制数据进行的运算(+、-、*、/)都是叫位运算,即将符号位共同参与运算的运算。
二、位运算过程
在计算机中运算是以二进制来进行,如下面所示的计算两数之和:
int a = 10;
int b = 12;
int c = a + b;
计算机在进行运算时,会先将 int型变量先转换成二进制形式再进行运算:
a 10: 0 0 0 0 1 0 1 0
b 12: 0 0 0 0 1 1 0 0
—————————————————————————————
c 22: 0 0 0 1 0 1 1 0
三、位运算类型
符号 | 描述 | 运算规则 |
---|---|---|
& | 与 | 两个位都为1才为1,否则为0 |
I | 或 | 两个位都为0才为0,否则为1 |
^ | 异或 | 相同为0,不同为1 |
~ | 取反 | 0变1,1变0 |
<< | 左移 | 各位都向左进行移位操作,高位丢弃,低位补0(左移一位,相当于乘2,移两位相当于乘2*2,n位为乘2的n次方) |
>> | 右移 | 各位都向右进行移位操作,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)(右移一位,相当于除2,右移n位,相当于除2的n次方 |
四、实际运用
- 清零
如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。
即xxxxxxxxxx&0=0 - 取一个数的指定位
比如取数 X=1010 1110 的低4位,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位与运算(X&Y=0000 1110)即可得到X的指定位。 - 判断数a的奇偶性
if((a&1)==1){
//a是奇数(因为奇数二进制末位为1,两位为1,与结果为1)
}
if((a&1)==0){
//a是偶数(因为偶数二进制末位为0,与结果为0)
- 判断数a的二进制中第n位为是否为1
if((a&(1<<(n-1)==0){
//a的二进制数第n位为0(利用与的运算规则,将1左移到要检测的位置,第n位要从第一位移动(n-1)位)
}else{
//a二进制数第n位为1
}
- 交换两个数(无需第三个数即中间数)
首先需要了解异或的性质
:
3.1交换律: a ^ b = b ^ a
3.2结合律: a ^ (b ^ c)=(a ^ b) ^ c
3.3 a ^ a=0 , a ^ 0=a
viod swap(int a,int b){
a^=b; //a=(a^b)
b^=a; //b=b^a=b^(a^b)=0^a=a
a^=b; //a=a^b=(a^b)^b=(a^b)^a=0^b=b
- 给一组整形数据,这些数据中,其中有一数只出现了一次,其他数据都出现了两次,找出只出现一次的数
int getsingle(int *nums,int numsSize){
int single
//如给定一个数组[1,2,5,1,2]
//常规解法:
//从一个任意的数组中找出只出现了一次的数,需要遍历数组,将数字出现的次数计数,最后返回计数为1的数字
//异或思路:使用性质: a ^ a=0,遍历数组,将每个数字进行异或累积
// 1^2^5^1^2=(1^1)^(2^2)^5=0^0^5=5
for (int i=0;i<numsSize;++i){
single^=nums[i];
}
return single;
}
- 两个整数相加
两数异或可以视作不进位的加和,在加和中只有当两数对应位都为1的情况下才会产生进位,而对应位都为1在与(&)的结果下都为1,再左移一位用来表示进位,那么a+b=(a^b)+(a&b)<<1
int a=12,b=10;
a 1100 1100 1100
b ^ 1010 & 1010 + 1010
————————————————————————————————————————————
c 0110 1000 10110
此题来源于力扣(LeetCode),如下面题目要求所示,不能使用运算符+和-
int getSum (int a, int b){
return b==0?a:getSum(a^b,(unsigned int)(a&b)<<1);
}