美文网首页
算法训练 -- 第一章 线性表

算法训练 -- 第一章 线性表

作者: 珺王不早朝 | 来源:发表于2021-01-01 21:06 被阅读0次
一、位操作

所有数据在计算机底层都是以二进制形式存在的
存储时:数据以二进制数字形式进行存储
计算时:数据以补码形式参与运算,计算结束后再将结果转换回原码

1. 原码与补码

原码:首位符号位 + 数值位
  5:0000 0000   0000 0000   0000 0000   0000 0101
 -5:1000 0000   0000 0000   0000 0000   0000 0101

反码:中间状态 -- 原码数值位按位取反,符号位不变
  5:0000 0000   0000 0000   0000 0000   0000 0101
 -5:1111 1111   1111 1111   1111 1111   1111 1010

补码:反码 + 1,符号位参与运算
  5:0000 0000   0000 0000   0000 0000   0000 0101
 -5:1111 1111   1111 1111   1111 1111   1111 1011

规律:
正数的 补码 == 原码,反之亦然
  负数的 补码 = 原码数值位按位取反 + 1
  负数的 原码 = 补码数值位 - 1 再按位取反

2. 位运算

&(按位与,and):两数补码逐位比较,同1为1,有0为0,符号位参与计算
| (按位或,or):两数补码逐位比较,有1为1,同0为0,符号位参与计算
^(按位异或,xor):两数补码逐位比较,不同为1,相同为0,符号位参与计算
~(按位取反,not):1变为0,0变为1(自运算)
<<(左移n位,shl):a << b -- 二进制数a的补码左移b位,右侧补0,符号位不变
>>(右移n位,shr):a >> b -- 二进制数a的补码右移b位,左侧补原符号位的值(即,正数补0,负数补1)
>>>(无符号右移n位):a >>> b -- 将二进制数a视为正数,再将其补码(即其自身)右移b位,左侧补0

特别注意:所有数据(底层存储为二进制数字)都是以其 二进制补码 形式参与位运算的!

例如,计算机中 -5 除以 4 应该等于多少呢?

代码测试:

public static void main(String[] args) {
    int a = -5;
    System.out.println(a + " 除以 4 等于 " + (a / 4) + " 余 " + (a % 4));
}

执行结果:

-5 除以 4 等于 -1 余 -1

而 -5 右移 2 位等于多少呢?结果还是 -1 吗?

代码测试:

public static void main(String[] args) {
    int a = -5;
    System.out.println(a + " 右移 2 位为 " + (a >> 2));
}

执行结果:

-5 右移 2 位为 -2

???(十分疑惑)
教科书上不是经常写:右移 1 位 == 除以 2;右移 2 位 == 除以 4 吗?
那为什么一个负数右移 2 位的结果和其除以 4 的结果不同呢?

这是因为 -5 在参与右移运算前,要先转换成二进制补码形式
原码:1000 0000   0000 0000   0000 0000   0000 0101
补码:1111 1111   1111 1111   1111 1111   1111 1011
补码右移 2 位,由于是负数,左侧补1
结果:1111 1111   1111 1111   1111 1111   1111 1110
由于结果是负数,因此其原码 = 补码 - 1 再按位取反,符号位不变
结果原码:1000 0000   0000 0000   0000 0000   0000 0010
结果对应的数字值为:-2

3. 位运算的应用

1)与运算 实现 取模运算
  33 % 16 = 1
  33 &(16 -1)= 1
2)与运算 实现 奇偶性判断
  5 & 1 = 1
  4 & 1 = 0
3)与运算 实现 取整数的二进制码中最低位的“1”所代表的数值
   -- 树状数组(BIT,二叉索引树)核心算法
  4 & -4 = 4   0000 0100 & 1111 1100 = 0000 0100
  5 & -5 = 1   0000 0101 & 1111 1011 = 0000 0001
  6 & -6 = 2   0000 0110 & 1111 1010 = 0000 0010
  7 & -7 = 1   0000 0111 & 1111 1001 = 0000 0001
  8 & -8 = 8   0000 1000 & 1111 1000 = 0000 1000
4)异或运算的 还原特性
  异或运算有类似于“负负得正”的特性:
  一个数与另一个数做两次异或运算后,结果与运算前相同,即:a ^ b ^ b == a
  这种性质可以在不使用中间变量的情况下交换两个整型变量的值

public static void main(String[] args) {
    int a = -5;
    int b = 4;
    a = a ^ b;
    b = a ^ b; // b = a ^ b ^ b = a
    a = a ^ b; // a = (a ^ b) ^ (a ^ b ^ b) = b
    System.out.println("a = " + a);
    System.out.println("b = " + b);
}

执行结果:

a = 4
b = -5

相关文章

网友评论

      本文标题:算法训练 -- 第一章 线性表

      本文链接:https://www.haomeiwen.com/subject/qykroktx.html