位运算(详细)

注:

  • 位运算一般是补码之间的位运算
  • 计算结果为补码,需要转原码
  • 下面案例中,数字均按 int 类型处理,占4字节
  • short 和 byte 类型数据在运算时,都会转为 int 类型
  • Java中,可以通过 Integer.toBinaryString() 方法,查看int类型数字在底层存储的补码
  • 以下案例均在 java 语言中测试

按位与(&)

将参加运算的两个数据,按二进制位进行"与"运算。

举例:3 & -5

3
原码	0000 0000 0000 0000 0000 0000 0000 0011
补码	0000 0000 0000 0000 0000 0000 0000 0011
-5
原码	1000 0000 0000 0000 0000 0000 0000 0101
补码	1111 1111 1111 1111 1111 1111 1111 1011

结果:3

补码	0000 0000 0000 0000 0000 0000 0000 0011
原码	0000 0000 0000 0000 0000 0000 0000 0011	=>	3

按位或(|)

将参加运算的两个数据,按二进制位进行"或"运算。

举例:3 | -5

3
原码	0000 0000 0000 0000 0000 0000 0000 0011
补码	0000 0000 0000 0000 0000 0000 0000 0011
-5
原码	1000 0000 0000 0000 0000 0000 0000 0101
补码	1111 1111 1111 1111 1111 1111 1111 1011

结果:-5

补码	1111 1111 1111 1111 1111 1111 1111 1011
原码	1000 0000 0000 0000 0000 0000 0000 0101	=>	-5

按位取反(~)

将参加运算的数据,按二进制位进行"取反"运算。符号位也取反

举例:~3

3
原码	0000 0000 0000 0000 0000 0000 0000 0011
补码	0000 0000 0000 0000 0000 0000 0000 0011

结果:-4

补码	1111 1111 1111 1111 1111 1111 1111 1100
原码	1000 0000 0000 0000 0000 0000 0000 0100	=>	-4

异或(^)

将参加运算的两个数据,按二进制位进行"异或"运算。相同为0,不同为1

举例:3 ^ -5

3
原码	0000 0000 0000 0000 0000 0000 0000 0011
补码	0000 0000 0000 0000 0000 0000 0000 0011
-5
原码	1000 0000 0000 0000 0000 0000 0000 0101
补码	1111 1111 1111 1111 1111 1111 1111 1011

结果:8

补码	1111 1111 1111 1111 1111 1111 1111 1000
原码	1000 0000 0000 0000 0000 0000 0000 1000	=>	8

运算法则

  • n ^ 0 = n
  • n ^ n = 0
  • a ^ b = b ^ a
  • a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;

d = a ^ b ^ c,a ^ b ^ a = b => a = d ^ b ^ c


例题

题目:找出只出现一次的数字

描述:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

普通写法:代码不简洁 且时间复杂度高


class Solution {
    public int singleNumber(int[] nums) {
        boolean flag;
        for (int i = 0; i < nums.length; i++) {
            flag = false;
            for (int j = 0; j < nums.length; j++) {
                if (nums[i] == nums[j] && i != j) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                return nums[i];
            }
        }
        return -1;
    }
}

异或写法

class Solution {
    public int singleNumber(int[] nums) {
        int n = 0;
        for(int i = 0; i < nums.length; i++){
            n ^= nums[i];   //异或运算
        }
        return n;
    }
}

同或

将参加运算的两个数据,按二进制位进行"同或"运算。相同为1,不同为0

注:Java 中没有同或运算符,但可以用异或运算符(^)和取反运算符(~)来实现同或运算

举例:~(3 ^ -5)

3
原码	0000 0000 0000 0000 0000 0000 0000 0011
补码	0000 0000 0000 0000 0000 0000 0000 0011
-5
原码	1000 0000 0000 0000 0000 0000 0000 0101
补码	1111 1111 1111 1111 1111 1111 1111 1011

结果:7

补码	0000 0000 0000 0000 0000 0000 0000 0111
原码	0000 0000 0000 0000 0000 0000 0000 0111	=>	7

左移位(<<)

按二进制形式把数字向左移动对应的位数,高位舍弃,低位补零,符号位一同移动

举例:131 << 24

131
原码	0000 0000 0000 0000 0000 0000 1000 0011
补码	0000 0000 0000 0000 0000 0000 1000 0011

结果:-2097152000

补码	1000 0011 0000 0000 0000 0000 0000 0000
原码	1111 1101 0000 0000 0000 0000 0000 0000	=>	-2097152000

面试题:最高效的计算 2 * 8?

2 << 3 或 8 << 1


右移位(>>)

按二进制形式把数字向右移动对应的位数,低位舍弃,高位补符号位(正数补0,负数补1)。

举例:131 >> 5

131
原码	0000 0000 0000 0000 0000 0000 1000 0011
补码	0000 0000 0000 0000 0000 0000 1000 0011

结果:5

补码	0000 0000 0000 0000 0000 0000 0000 0100
原码	0000 0000 0000 0000 0000 0000 0000 0100	=>	5

举例:-131 >> 1

-131
原码	1000 0000 0000 0000 0000 0000 1000 0011
补码	1111 1111 1111 1111 1111 1111 0111 1101

结果:-66

补码	1111 1111 1111 1111 1111 1111 1011 1110
原码	1000 0000 0000 0000 0000 0000 0100 0010	=>	-66

无符号右移位(>>>)

按二进制形式把数字向右移动对应的位数,低位舍弃,高位补0

举例:-131 >>> 1

-131
原码	1000 0000 0000 0000 0000 0000 1000 0011
补码	1111 1111 1111 1111 1111 1111 0111 1101

结果:2147483582

补码	0111 1111 1111 1111 1111 1111 1011 1110
原码	1000 0000 0000 0000 0000 0000 0100 0010	=>	2147483582

参考文章:https://blog.csdn.net/w7486/article/details/119614008

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值