位运算以及位图

计算机中的数在内存中都是以二进制形式进行存储的,用位运算就是直接对整数在内存中的二进制位进行操作,因此其执行效率非常高,在程序中尽量使用位运算进行操作,这会大大提高程序的性能。

位操作符

与&

1 0 0 1 1 
1 1 0 0 1 
------------------------------
1 0 0 0 1

与运算 两个位都是 1 时,结果才为 1,否则为 0

或 |

1 0 0 1 1 
1 1 0 0 1 
------------------------------
1 1 0 1 1

或运算 两个位都是 0 时,结果才为 0,否则为 1

异或运算 ^

即无进位相加

  1. 0 ^ N = N, N ^ N = 0

  2. 异或运算满足交换律与结合律

使用无进位相加理解上述两个性质非常容易

取反运算 ~

左移运算 <<

  • 对一个数进行左移一次相当于 * 2

  • 左移n次,相当于* (2 ^ n)

右移运算 >>

  • 对一个数右移一次相当于 / 2

  • 右移n次,相当于 / (2 ^ n)

无符号右移运算 >>>

负数的表示

计算机32位int值,如果是无符号整型,可以表示的数字范围位0 ~ 2^32-1,如果是有符号整型,可表示的数字范围为-2^31 ~ 2^31-1,包含0,他们都共可以表示 2 ^ 32个数字。

无符号整型将所有32位都作为值存储,而有符号整型则将最高位作为符号位,当符号位为0代表该数字为非负数(可能为0以及正数),如果符号位数字为1,代表该数字为负数,比如在Java中:

负数二进制表示的计算:

取反加一就是二进制的补码。

为什么负数要使用二进制补码的形式?

参考:https://blog.csdn.net/leonliu06/article/details/78685197

总结:一种巧妙地设计,也是一种规定,为了提高二进制计算的效率

常见的位运算问题

32位int转换为二进制字符串

说明:便利32位int的每一位,将每位的状态打印。比如,第一位与 100....00相与,可得到该数第一位的状态;第二位与0100...0相与,可得到第二位的状态,一直到第最后一位,从 31 到 0。

交换数字(异或)

原理:

注意:

判断奇偶数

正负切换(补码)

绝对值

高低位交换

统计二进制中 1 的个数

统计二进制1的个数可以分别获取每个二进制位数,然后再统计其1的个数,此方法效率比较低。这里介绍另外一种高效的方法,同样以 34520 为例,我们计算其 a &= (a-1)的结果:

  • 第一次:计算前:1000 0110 1101 1000 计算后:1000 0110 1101 0000

  • 第二次:计算前:1000 0110 1101 0000 计算后:1000 0110 1100 0000

  • 第二次:计算前:1000 0110 1100 0000 计算后:1000 0110 1000 0000 我们发现,没计算一次二进制中就少了一个 1,则我们可以通过下面方法去统计:

位运算实现加减乘除

计算机底层都是使用位运算实现加减乘除。

加法

java实现:

减法

乘法

乘法的实现方式是乘法的竖式表达程序化:

程序化:

除法

使用除2的方式是因为2可以使用位运算替代。这种方式实际就是不断的减去被除数,并计算被减的次数。

Java代码实现如下:

控制某一位

假设有二进制数1011 0110

  1. 控制这个二进制数的最高位变为0:

  2. 控制这个二进制数的最低位变为1:

java实现:

位图的实现

Java:

面试题

异或

一个数组中有一个数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这个数字?

原理:

  1. 满足交换律,所以 4, 1, 3, 3, 2, 1, 3, 1, 2, 3, 2, 1, 4即为:1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4

  2. 相同的数字异或为0, 所以上述数字偶数个的都会被异或为0,奇数个的最中会剩余一个数字


怎么将一个int类型的数,提取出他二进制最右侧的1来?

推算过程:


一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数?


找到数字N的二进制的含有1的数量?

最后更新于

这有帮助吗?