令人赞叹的位运算

时间:2022-07-23
本文章向大家介绍令人赞叹的位运算,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

想必大家每次阅读第三方源码时,都觉得其中的位运算很酷,让人神往又抓狂。为了搞懂那些操作的具体含义,想去深入了解那些魔法代码背后的原理。

之前我也写过一篇文章谈了一些面试中可能遇到的算法题,今天更多的是一些用法的总结。

我们先回顾下常见的位运算符:

  • & 与运算 两个位都是 1 时,结果才为 1,否则为 0, 如 :1 0 0 1 1 & 1 1 0 0 1 =1 0 0 0 1
  • |或运算 两个位都是 0 时,结果才为 0,否则为 1, 如 :1 0 0 1 1 | 1 1 0 0 1 =1 1 0 1 1
  • ^ 异或运算,两个位相同则为 0,不同则为 1, 如 :1 0 0 1 1 ^ 1 1 0 0 1 =0 1 0 1 0
  • ~ 取反运算,0 则变为 1,1 则变为 0, 如:~ 1 0 0 1 1 =0 1 1 0 0

然后我们再来看看一些常见的技巧。

一,我们知道我们的字符在计算机底层都是数字表示的,恰巧英文字符在ASCII 编码里通过位运算就能进行大小写转换。

  1. 利用或操作 | 和空格将英文字符转换为小写。 ('a' | ' ') = 'a' ('A' | ' ') = 'a'
  2. 利用与操作 & 和下划线将英文字符转换为大写。 ('b' & '') = 'B'` `('B' & '') = 'B'
  3. 利用异或操作 ^ 和空格进行英文字符大小写互换。 ('d' ^ ' ') = 'D' ('D' ^ ' ') = 'd'

二,异或的性质非常方便

  1. 可以判断两个数是否异号: int x = -1, y = 2; boolean f = ((x ^ y) < 0); // true int x = 3, y = 2; boolean f = ((x ^ y) < 0); // false
  2. 也可以用来交换两个数:
int a = 1, b = 2;
a ^= b;
b ^= a;
a ^= b;
// 现在 a = 2, b = 1 

三,判断奇偶数

  • 只要根据数的最后一位是 0 还是 1 来决定即可,为 0 就是偶数,为 1 就是奇数。 ``` if(0 == (a & 1)) { //偶数 }
四,符号交换
* 交换符号将正数变成负数,负数变成正数。

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

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

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

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

六,取反实现+1,-1(不过我感觉没啥用)

int n = 1; n = -~n; // 现在 n = 2

```
int n = 2;
n = ~-n;
// 现在 n = 1

七,位操作统计二进制中 1 的个数 统计二进制1的个数可以分别获取每个二进制位数,然后再统计其1的个数,此方法效率比较低。不过 n & (n - 1) 可以消除最后一个 1,所以可以用一个循环不停地消除 1 同时计数,直到 n 变成 0 为止。

while (n != 0) {
        n = n & (n - 1);
        res++;
    }

怎么样,是不是感觉自己奇怪的知识又增加了??总体而言,虽然这些技巧有的提高了性能,有的简化了代码,但不是所有代码都那么好理解,大家还需要结合实际场景去理解这些技巧,从实际的题目中去找到它们的优势,它们的意义。happy coding~