位运算技巧总结

专栏原创出处:github-源笔记文件 github-源码 ,欢迎 Star,转载请附上原文出处链接和本声明。

有哪些位运算

  • & 与运算 两个位都是 1 时,结果才为 1,否则为 0
  • | 或运算 两个位都是 0 时,结果才为 0,否则为 1
  • ^ 异或运算,两个位相同则为 0,不同则为 1
  • ~ 取反运算,0 则变为 1,1 则变为 0
  • << 左移运算,向左进行移位操作,高位丢弃,低位补 0(部分语言支持无符号左移 <<<
  • >> 右移运算,向右进行移位操作,对无符号数,高位补 0,对于有符号数,高位补符号位(部分语言支持无符号右移 >>>

位移实现乘除法

int a = 2;
a >> 1; ---> 1
a << 1; ---> 4

a ^ b ^ b = a 异或交换两数

// 案例:数字替换
//普通操作
void swap(int &a, int &b) {
  a = a + b;
  b = a - b;
  a = a - b;
}

//位与操作
void swap(int &a, int &b) {
  a ^= b;   // a = (a^b);
  b ^= a;   // b^(a^b) --> b = (b^b)^a = a
  a ^= b;   // (a^b)^a = (a^a)^b = b
}

应用:

  • 数组中,只有一个数出现一次,剩下都出现两次,找出出现一次的数
  • 数组中,只有一个数出现一次,剩下都出现三次,找出出现一次的
  • 数组中,只有两个数出现一次,剩下都出现两次,找出出现一次的

与运算判断奇偶数

只要根据数的最后一位是 0 还是 1 来决定即可,为 0 就是偶数,为 1 就是奇数。

0 == (a & 1)  偶数
1 == (a & 1)  奇数

取反运算交换符号

交换符号将正数变成负数,负数变成正数。

整数取反加 1,正好变成其对应的负数 (补码表示);负数取反加一,则变为其原码,即正数

int reversal(int a) {
  return ~a + 1;
}

位操作求绝对值

整数的绝对值是其本身,负数的绝对值正好可以对其进行取反加一求得,即我们首先判断其符号位(整数右移 31 位得到 0,负数右移 31 位得到 -1,即 0xffffffff),
然后根据符号进行相应的操作。

int abs(int a) {
  int i = a >> 31;
  return i == 0 ? a : (~a + 1);
}

上面的操作可以进行优化,可以将 i == 0 的条件判断语句去掉。我们都知道符号位 i 只有两种情况,即 i = 0 为正,i = -1 为负。
对于任何数与 0 异或都会保持不变,与 -1 即 0xffffffff 进行异或就相当于对此数进行取反,因此可以将上面三目元算符转换为 ((a^i)-i)。

  • 整数时 a 与 0 异或得到本身,再减去 0
  • 负数时与 0xffffffff 异或将 a 进行取反,然后在加上 1,即减去 i(i=-1)
int abs2(int a) {
  int i = a >> 31;
  return ((a^i) - i);
}

位操作进行高低位交换

给定一个 16 位的无符号整数,将其高 8 位与低 8 位进行交换,求出交换后的值。

只要将无符号数 a>>8 即可得到其高 8 位移到低 8 位,高位补 0;将 a<<8 即可将 低 8 位移到高 8 位,低 8 位补 0,然后将 a>>8 和 a<<8 进行或操作既可求得交换后的结果。

a = (a >> 8) | (a << 8);

消去二进制最后一位的 1

x & (x - 1) 用于消去 x 最后一位的 1

x = 1100
x - 1 = 1011
x & (x - 1) = 1000

// 案例:位操作统计二进制中 1 的个数
int count = 0  
while(a != 0){  
  a = a & (a - 1); // 每次计算 a 少一个 1
  count++;  
} 

应用:

  • 检测 n 是否为 2 的幂次。(大于 0,二进制只有一个 1)
  • 位操作统计二进制中 1 的个数(每次消去一个,消到为 0)

参考

更多相关专栏内容汇总:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值