位运算以及位图
计算机中的数在内存中都是以二进制形式进行存储的,用位运算就是直接对整数在内存中的二进制位进行操作,因此其执行效率非常高,在程序中尽量使用位运算进行操作,这会大大提高程序的性能。
位操作符
与&
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异或运算 ^
即无进位相加
0 ^ N = N,N ^ N = 0异或运算满足交换律与结合律
使用无进位相加理解上述两个性质非常容易
取反运算 ~
左移运算 <<
对一个数进行左移一次相当于
* 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:
控制这个二进制数的最高位变为0:
控制这个二进制数的最低位变为1:
java实现:
位图的实现
Java:
面试题
异或
一个数组中有一个数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这个数字?
原理:
满足交换律,所以
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相同的数字异或为0, 所以上述数字偶数个的都会被异或为0,奇数个的最中会剩余一个数字
怎么将一个int类型的数,提取出他二进制最右侧的1来?
推算过程:
一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数?
找到数字N的二进制的含有1的数量?
最后更新于
这有帮助吗?