位运算的妙用

375 阅读2分钟

每四位2进制数字可以组成一个16进制数

要先了解优先级

与运算(&)的使用场景

  1. 清零

    ​ 如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。

  2. 一个数的指定位

    ​ 比如取数 X=1010 1110 的低4位,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位与运算(X&Y=0000 1110)即可得到X的指定位。

  3. 判断奇偶

    ​ 只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((a & 1) == 0)判断奇偶。

  4. 获取一个数字的二进制有几个1

    ​ 使用(n - 1) & n,该式子的作用是把二进制数字最右边的1变成0,能变多少次,则有多少个1。

或运算(|)的使用场景

  1. 常用来对一个数据的某些位设置为1

    ​ 比如将数 X=1010 1110 的低4位设置为1,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位或运算(X|Y=1010 1111)即可得到。

异或(^)

先明确异或的性质:

  • 交换律
  • 结合律 (a ^ b) ^ c = a ^ (b ^ c)
  • 对于任何数x,都有x ^ x = 0,x ^ 0 = x
  • 自反性 a ^ b ^ b = a ^ 0 = a

场景:

  1. 翻转指定位

    ​ 比如将数 X=1010 1110 的低4位进行翻转,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行异或运算(X^Y=1010 0001)即可得到。

  2. 与0相异或值不变

  3. 交换两数(比较重要)

    1. void swap(int[] arr, int a, int b) {
          //不要下面那个判断也可以
          if(a != b) {
              a ^= b;
              b ^= a;
              a ^= b;
          }
      }
      
      void swap(int[] arr, int pos1, int pos2) {
          //有陷阱(当俩下标相等时,会把这个下标的值变成0)
          arr[pos1] ^= arr[pos2];
          arr[pos2] ^= arr[pos1];
          arr[pos1] ^= arr[pos2];
      }
      

取反(~)运算符

  1. 使一个数的最低位为零

    ​ 使a的最低位为0,可以表示为:a & ~ 1。~ 1的值为 1111 1111 1111 1110,再按"与"运算,最低位一定为0。(~的优先级高于&)

左移运算符(<<)

  1. 只要不溢出,左移运算 << n 就相当于乘上 2n2^n,并且左移运算会比乘法快,尤其是n > 1的情况。

右移运算符(>>)

  1. 只要不溢出,<< n 就相当于除以 2n2^n,并且右移运算会比除法快,尤其是n > 1的情况。