位运算基本操作:
- & (与):都为1结果才为1
- | (或):有一个为1结果就为1
- ~ (非):0变成1,1变成0
- ^(异或):两者不相同时才为1
- (>>):右移运算符,将二进制位进行右移,右移一位相当于除以2
- (<<):左移运算符,将二进制位进行左移,左移一位相当于乘2
- (>>):将用符号位来填充高位
- 对于int型,1<<35与1<<3是相同的(因为int32位需要对32取模),而左边的操作数是long型时需要对64取模
关于异或的一些性质:
- 交换律,可任意交换因子的位置,结果不变
- 结合律,即(a^ b)^ c == a ^ (b ^ c)
- 对于任何数x,都有x^x=0,x ^0=x,同自己求异或等于0,同0求异或为自己
- 自反性,A ^ B ^ B=A ^ 0 = A,连续和同一个因子做异或运算,最终结果为自己
利用位运算的一些小技巧:
1. 判断奇偶数
对于奇数来说,二进制的最后一位一定为1,而对于偶数来说,二进制的最后一位一定为0,所以判断一个数是奇数还是偶数直接和1进行与运算就可以了
#include <iostream>
using namespace std;
int main()
{
int num;
cin>>num;
if(num&1)
cout<<num<<"为奇数"<<endl;
else
cout<<num<<"为偶数"<<endl;
return 0;
}
2. 交换两个整数变量的值
给定两个整数A和B,要求交换两个数的值,常规方法就是再定义一个变量,然后进行交换,而最高效的方法仍是位运算。
A=A ^ B
B=A ^ B (此时B=(A ^ B)^B = A)
A=A ^ B (此时A= (A ^ B)^A = B)
由此,便完成了A和B的交换
#include <iostream>
using namespace std;
int main()
{
int a,b;
cin>>a>>b;
a=a^b;
b=a^b;
a=a^b;
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
return 0;
}
3. 获取二进制位是1还是0
例如给定一个数a,要求求出该数二进制第x位为1还是为0
此时直接将该数第k位与1进行与运算即可,也就是将1左移k-1位,然后和该数进行与运算,为1,则说明第x位为1,为0则说明第x位为0
num&(1<<k-1)
#include <iostream>
using namespace std;
int main()
{
int num,k;//k表示num的第k位
cin>>num>>k;
if(num&(1<<k-1))
cout<<num<<"的第"<<k<<"位为:1"<<endl;
else
cout<<num<<"的第"<<k<<"位为:0"<<endl;
return 0;
}
4. 求整数的绝对值
如何不使用判断语句而求得一个数的绝对值,此时又用到了位运算
一、对于正数来说,它的符号位为0,因此对正数进行(带符号<<)右移31位,将得到全0,此时值为0。正数的绝对值是其本身
二、对于负数来说,他的符号位为1,因此对负数进行(带符号<<)右移31位,将得到全1,此时值为-1(因为计算机中是以补码来存储的)。负数的绝对值正好可以对其进行取反加一求得。
int t=(a>>31);
如果a是正数,则t为0,a为负数,则t为-1
int ans=(a^t)-t;
a为正数,绝对值就是其本身
a为负数时,a^t就是对a进行按位取反,t为-1,
减去t就是加上1,从而得到其绝对值。
#include <iostream>
using namespace std;
int main()
{
int a;
cin>>a;
int t=(a>>31);
int ans=(a^t)-t;
cout<<ans<<endl;
return 0;
}
5. 求数字中1的个数
求一个数字的二进制中1的个数,有两种方法
(1)int型数字是32位的,因此for循环32次,将该数字和1左移k位进行与运算,得到的结果的1左移k位相等,则说明该数字第k位为1.
#include <iostream>
using namespace std;
int main()
{
int n;
cin>>n;
int cnt=0;
for(int i=0;i<32;i++)
{
if((n&(1<<i))==(1<<i))
cnt++;
}
cout<<cnt<<endl;
return 0;
}
(2)假设这个数字为的二进制为10100,先将该数字减一,变为10011,(可以发现只要每减一次1,该数字最低位的1变为0,该位后边全变位1),将10011和10100进行与运算为10000,消去了一个1,因此可以记录消去1的个数直至该数字为0.
#include <iostream>
using namespace std;
int main()
{
int n;
cin>>n;
int cnt=0;
while(n)
{
n=(n-1)&n;
cnt++;
}
cout<<cnt<<endl;
return 0;
}