位操作总结


在计算机中所有数据都是以二进制的形式储存的。位运算其实就是直接对在内存中的二进制数据进行操作,因此处理数据的速度非常快。

一、二进制的表现形式

计算机内部存储、计算的任何信息都是由二进制(0和1)表示,而二进制有三种不同的表示形式:原码反码补码。计算机内部使用补码来表示。

  • 原码:其二进制表示(有一位符号位)

  • 反码:正数的反码就是原码,负数的反码是符号位不变,其余位取反

  • 补码:正数的补码就是原码,负数的补码是反码+1

符号位,最高位为符号位,0表示正数,1表示负数。在位运算中符号位也参与运算。

二、基本位操作

基本的位操作符有与、或、异或、取反、左移、右移这6种,如下所示:

符号 描述
& 按位与
按位或
^ 按位异或
~ 按位非
<< 左移
>> 右移

按位与&

运算规则:其中两位都为1结果为1,其他情况为0

运算符:二目运算符

示例:

3 & 17 = 1
3 = 00000011
17 = 00010001
3 & 17 = 00000001

按位或

运算规则:两个位都为0时,结果才为0,至少有1位为1结果就为1

运算符:二目运算符

示例:

3 | 17 = 19
3 = 00000011
17 = 00010001
3 | 17 = 00010011 

按位异或^

运算规则:两个位相同为0,相异为1

运算符:二目运算符

示例:

3 ^ 17 = 18
3 = 00000011
17 = 00010001
3 ^ 17 = 00010010

小技巧

异或是不进位加法,两个数做加法,把进位舍去

按位非

运算规则:对操作数进行按位取反,原来为1结果为0,原来为0结果为1。

运算符:单目运算符

示例:

9 = -10
转二进制:0 1001
计算补码:0 1001
按位取反:1 0110
转为原码:
按位取反:1 1001  
末位加一:1 1010
符号位为1是负数,即 ~9 = -10

小技巧

所有正整数的按位取反是其本身+1的负数

所有负整数的按位取反是其本身+1的绝对值

零的按位取反是 -1

左移<<

运算规则:把操作数整体向左移动

运算符:二目运算符

示例:

33 << 2 = 00100001 << 2 = 10000100 = 132

小技巧

$a << n = a * 2^n$ (a为正数)

右移>>

运算规则:把操作数整体向右移动

运算符:二目运算符

示例:

33 >> 2 = 00100001 >> 2 = 00001000 = 8

小技巧

$a >> n = a / 2^n$ (a为正数)

位操作只能用于整形数据,对float和double类型进行位操作会被编译器报错。

三、常用的位操作技巧

1、判断奇偶数

只需要判断已知数的二进制数末尾是0还是1,如果为0就是偶数,为1就是奇数。

求0-50之间所有的偶数代码示例如下:

for (int i = 0; i < 50; i++) {
  if ((i & 1) == 0) {
    System.out.println("0-50之间所有的偶数:" + i);
  }
}

2、不用加减乘除做加法

异或是按位相同为0不同为1,其实就是做加法的过程把进位舍去了。如果两数相加没有进位就直接可以使用异或,如果有进位,就把进位加上。

有进位的地方就是两个位都为1的地方,这就可以利用按位与运算了,把两数相与的结果左移一位就是进位的结果。

a + b = (a ^ b) + ((a & b) << 1)

不用加减乘除做加法的代码示例如下:

// 循环法1
class Solution {
    public int add(int a, int b) {
        while(b != 0) { // 当进位为 0 时跳出
            int c = (a & b) << 1;  // c = 进位
            a ^= b; // a = 非进位和
            b = c; // b = 进位
        }
        return a;
    }
}

// 递归法2
public class Solution {
    public int Add(int num1,int num2) {
        if (num2 == 0) return num1;
        return Add(num1 ^ num2, (num1 & num2) << 1);
    }
}

3、只出现一次的数字

两个相同的数异或为0,一个数和0异或结果不变,那么异或两次相当于没有异或,即a ^ b ^ b = a

给一个数组,数组中的数字只有一个出现了一次,其他的都出现了两次,找出这个只出现一次的数字,代码示例如下:

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for (int i : nums) {
            res ^= i;
        }
        return res;
    }
}

4、交换两数

https://blog.csdn.net/MoreWindows/article/details/7354571

https://www.cnblogs.com/wxisme/p/8858514.html


评论
评论
  目录