位运算技巧合集【Java】

参考文章:

  1. Java 位运算(移位、位与、或、异或、非)
  2. 力扣官方知乎回答:位运算有什么奇技淫巧?

1. 基础运算

1.1 左移 << :二进制x左移i位,后面补0

x << i
5 << 20000 0101 << 20001 010020

正数或者负数左移,低位都是用0补。

1.2 右移 >> :二进制x右移i位,正数前面补0,负数前面补1

x >> i
5 >> 20000 0101 >> 20000 00011

1.3 无符号右移 >>> : 无论正负,前面补0

x >>> i
-5 >> 31111 1111 1111 1111 1111 1111 1111 1011 >> 31111 1111 1111 1111 1111 1111 1111 1111-1
-5 >>> 31111 1111 1111 1111 1111 1111 1111 1011 >>> 30001 1111 1111 1111 1111 1111 1111 1111536870911

1.4 按位与(&)

每一位做比较,都为1则为1,其中一个为0就为0。
(第一个操作数的的第n位于第二个操作数的第n位如果都是1,那么结果的第n为也为1,否则为0。)

5 & 3

	0101
&	0011
————————————
	00011

1.5 按位或(|)

每一位做比较,两个中有一个为1则为1,否则为0。
(第一个操作数的的第n位于第二个操作数的第n位 只要有一个是1,那么结果的第n为也为1,否则为0)

5 | 3

	0101
|	0011
————————————
	01117

1.6 按位异或(^)

相反为1, 相同为0
(第一个操作数的的第n位于第二个操作数的第n位 相反,那么结果的第n位也为1,否则为0)

5 ^ 3

	0101
^	0011
————————————
	01106

1.7 按位非(~)

~为一元操作符

1和0倒过来。
(操作数的第n位为1,那么结果的第n位为0,反之。)

~5

	0000 0000 0000 0000 0000 0000 0000 0101
~
————————————————————————————————————————————————
	1111 1111 1111 1111 1111 1111 1111 1010-6

1.8 赋值操作

类似于 +=

&= 按位与赋值
|= 按位或赋值
^= 按位异或赋值
>>=右移赋值
>>>= 无符号右移赋值
<<= 赋值左移

2. 常见位运算问题

2.1 位操作实现乘除法

  • 数 a 向右移一位,相当于将 a 除以 2;
  • 数 a 向左移一位,相当于将 a 乘以 2
int a = 2;
a >> 1;1
a << 1;4

2.2 位操作交换两数

三次异或

void swap(int a, int b){
	a ^= b; // a = a^b
	b ^= a; // b = b^(a^b) ⇒  b^b^a = a
	a ^= b; // a = (a^b)^b ⇒ a^a^b = b
}

2.3 位操作判断奇偶数

  • 最后一位是0 ⇒ 偶数
  • 最后一位是1 ⇒ 奇数

整数和1与运算,判断最后一位。

if(0 == (a & 1)) ⇒ 偶数
1: 只有最后一位是1,其他位都是0,所以进行与运算可以使a的其他位为0,判断最后一位是否为1/0

2.4 位操作交换符号

  • 将正数变负数、负数变正数。

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

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

2.5 位操作求绝对值

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

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

上面的操作可以进行优化,将i == 0的条件判断语句去掉。

  • 如果符号位i为0,正数,(a^i) - i= a
  • 如果符号位i为-1,负数,(a^i)- i = a ^ (-1) + 1 = a取反+1
int abs(int a) {
	int i = a >> 31;
	return ((a^i) - i);
}

2.6 位操作进行高低位交换

给定一个16位的无符号整数,将其高8位与低8位交换,求出交换后的值

a = 3452010000110 11011000
a = (a >> 8) | (a << 8)
	5543011011000 10000110

2.7 位操作进行二进制逆序

将无符号数的二进制表示进行逆序,求取逆序后的结果。

在字符串逆序过程中,可以从字符串的首尾开始,依次交换两端的数据。在二进制中使用位的高低位交换会更方便进行处理,这里我们分组进行多步处理。

    1. 第一步:以每 2 位为一组,组内进行高低位交换
    1. 第二步:在上面的基础上,以每 4 位为 1 组,组内高低位进行交换
    1. 第三步:以每 8 位为一组,组内高低位进行交换
    1. 第四步:以每16位为一组,组内高低位进行交换
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值