【数据结构】位运算

1,概念

1)运算规律

①与(&)

a&b

a、b两个运算式都要计算,最后与运算,不存在短路计算。

举例:(123456>>8) & 0xFF
将123456右移8位,然后截断取后8位。
由于java没有unsigned类型,所以为了适应与其他语言二进制通讯时各种数据的一致性,需要做一些处理。即将 有符号数转换为无符号数。

a&&b

如果a假就不再计算b,存在短路计算。

②或(|)

同理,| 没有短路计算,|| 有短路计算。

③异或(^)

0^0=0 1^0=1 1^1=0

④左移(<<)

⑤右移(>>)

>>带符号右移 
>>>无符号右移,左边空缺补充为0

2)应用规则

①a&(a-1)

一个整数减去1,在与原整数做与运算的结果会将最右边的1变为0,直到a = 0。这样可以操作的次数就是1的个数。

②提高效率

用右移运算符代替了除以2,用位运与算符代替求余运算(%)来判断一个数是奇数还是偶数。

3)优先级

java中:
逻辑运算符的优先级 ()> not > and > or
and or 遵循短路原则

2,原码、反码、补码

1)原码

第一位为符号位,其它为值。0为正,1为负。

2)反码

正数反码为其本身;
负数反码:符号位不变,其它各位取反。

~10表示10各位取反。

3)补码

正数补码:本身。
负数补码:原码的符号位不变,其它各位取反,最后加1.
即:从后数第一个1之后,各位取反。

注意:计算机用补码存储

4)例子

例一:

int i = 5;
int j = 10;
System.out.println(i + ~j); //5+(-11)=-6

j = 10,原码为(10)b = 0000 0000 0000 0000, 0000 0000 0000 1010;
(~10) = 1111 1111 1111 1111,1111 1111 1111 0101;(即各位取反)
因为计算机以补码存储,在读取时,补码为(~10)的数原码为:
1000 0000 0000 0000,0000 0000 0000 1011;即-11

例二:
变量a、b是64位有符号正数,a:0X 7FFF FFFF FFFF FFFF;b:0X 8000 0000 0000 0000;则a+b = ?

解答:
a+b = 0X FFFF FFFF FFFF FFFF FFFF;是-1的补码。

3,应用

1)二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路:
方案一:a&(a-1)(一个整数减去1,在与原整数做与运算)的结果会将最右边的1变为0,直到a = 0。这样可以操作的次数就是1的个数。
方案二:将a&1 != 0,然后右移1位,但不能计算负数的值.

    public int NumberOf1(int n) {
        int count = 0;
        while (n != 0) {
            count++;
            n = (n-1) & n;
        }
        return count;
    }

注意:java是32位机,-20 = 11111111111111111111111111101100(b)。

2)判断一个整数是不是2的整数次方

如果一个整数是2的整数次方,那么它的二进制表示中有且只有一位是1,而其他所有位都是0。题目转化为判断二进制有几个1。

3)输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。

比如10 = 1010(b) 13=1101(b),需要改变3位。
思路:首先,求这两个数的异或。第二步,统计异或结果中1的位数。

你可能感兴趣的:(数据结构)