1. 位运算基本操作
逻辑运算
a = 1 0 0 1 1
b = 1 1 0 0 1
与运算 & a & b = 1 0 0 0 1 //都为1时为1,否则为0
或运算 | a | b = 1 1 0 1 1 //都为0时为0,否则为1
非运算 ~ ~ a = 0 1 1 0 0 //所有位1变成0,0变成1
异或 ^ a ^ b = 0 1 0 1 0 //相同为0,不同为1
移位操作:左移和右移
对于左移,直接丢弃高位,低位补0即可;但是对于右移,丢弃低位,高位应该补什么?此时出现两种右移方式,算术右移和逻辑右移
算术右移:左端补上最高位
逻辑右移:左端直接补0
几乎所有的编译器/机器组合都对有符号数使用算术右移,而程序员编写程序时也都假设机器是这样实现的;对于无符号数,右移必须是逻辑的。
2. 巧妙使用位运算
1. 乘除
int a = 4;
a >> 1; //a=2
a << 2; //a=8
2. 交换
、void swap (&a,&b){
a ^= b;
b^ = a;
a ^= b;
3. 奇偶校验
if(0==a&1) //为真则是奇数,为假则是偶数
4. 正负数转换
int reverse(int a){
return ~a+1;
}
5. 求绝对值
int abs(int a){
int i = a>>31; //根据符号位判断正数还是负数
return i==0 ? a : (~a+1); //正数直接输出。负数取反加1
}
优化方法:
int abs(int a){
int i = a >>31; //正数则i=0,负数则i为Oxffffffff
return ((a ^ i)- i); //与Ox异或相当于取反,再-i其实就是加1
6. 高低位互换
unsigned short a = 34543; //只适用于无符号数
a = (a >> 8 | a << 8);
7. 统计二进制表示中1的个数
int a = 13
int count = 0;
while(a){
a = a & (a - 1);
count++;
}
第一次循环
a = 1 1 0 1
a-1 = 1 1 0 0
容易看出低位的1直接没了,a = 1 1 0 0
第二次循环
a = 1 1 0 0
a-1 = 1 0 1 1
再次消掉低位的1,循环往复即可
3. bitset 使用
头文件 #include
1. 初始化
bitset<16>bits; //0000000000000000
bitset<16>bits(Oxff); //1111111111111111
bitset<16>bits(std::string("001100110011")); //0000001100110011
2. 常用函数
bits.size() //位数
bits.none() //返回是否没有1
bits.any() //返回是否有1
bits.count() //返回1的个数
bits.set() //全部置1
bits.reset() //全部置0
bits.set(p)/bits.reset(p) //第p+1位置1/0
bits.flip() //全部取反
bits.flip(p) //第p+1位取反
bits.to_string() //返回转换后的字符串