算法入门 --- 位运算

α. 位运算的定义

数据在计算机里以二进制的形式存在,所谓位运算便是直接对数据在内存中的二进制位进行操作.

β. 位运算的形式(参与运算的数以补码进行运算)

β1. &(位与)

1 & 1 = 1
0 & 1 = 0
1 & 0 = 0
0 & 0 = 0
我们常常利用 & 运算把 0 消掉,而保持其他位的1不变,除此之外,我们还可以判断一些数的性质,下面会提到.

a & b = 1 (当且仅当a,b均为1)

β2. |(位或)

1 | 1 = 1
0 | 1 = 1
1 | 0 = 1
0 | 0 = 0

a | b = 0 (当且仅当a,b均为0)

β3. ^(位异或)

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

a ^ b = 1(当且仅当a=b)

β4. << >> (位左移,位右移)

左移(a<<b):将a向左移b位,后面补0,左移的结果为a增大2^b倍

aba<<b
0000000 00000000 00000000 0101100030000000 00000000 00000010 11000000
88增大8倍704

右移(a>>b)
如果a为正整数, 将a带符号向右移b位,高位补零,右移的结果为a的2^b倍.
如果a为负整数,右移的结果为a/2的b次方向上取整,具体解释可以参考这篇文章—>传送门

aba>>b
0000000 00000000 00000000 0101100030000000 00000000 00000000 01011000
88减小8倍11
10000000 00000000 00000000 01100100410000000 00000000 00000000 00000111
-100减小16倍-7

对于正整数来说,左移右移的操作和乘或者除2的幂次的效果是一样的,我们经常可以用位运算代替乘除法,因为位运算更底层,乘法和除法的本质也就是多次位运算,相比较而言,直接使用位运算速度更快.

β5. ~ (取反)

~0 = 1
~1 = 0

γ. 位运算的巧妙应用

γ1. 判断奇偶性(n&1)

一般我们判断数据的奇偶性时,会通过整数能否被2整除来判断,但从二进制形式来看,对于一个奇数,它的二进制形式最后一位一定是一(最右边一位权值为1,其他权值均为2的正整数倍),如果最右边一位为一,它肯定不能被2整除,即为奇数,反之为偶数.

判断一个数二进制形式最右边一位是否为1可以用到 & ,对于一个数 n,n & 1的结果便是把其最后一位取出来,我们再进行判断0 | 1 即可

  11001
& 00001
  ——————
  00001

所以在编程时,我们可以使用位运算来代替取余判断

    if (n % 2 == 0) { // 如果为偶数

    }
    if (n & 1) { // 如果为奇数

    }
γ2. 快速乘,快速幂

这里我请参考我的另一篇文章—>传送门,大致思想就是通过位运算,将计算a*b 以及a^b的计算时间复杂度转换为O(log(n)).

γ3. 判断一个数是否为2的指数幂(n&(n-1))

正常情况下我们判断一个数是否为2的指数幂的思路为:一直被2整除直到结果变成1或者非1奇数,这种思路的时间复杂度为O(log(n)),而使用位运算可以达到O(1)的效果.
一个二次幂的正整数n,它的二进制形式(不考虑存储的位数),为最左边一个1,接着右边全为0,而对于n-1,它相较于n最左边变为0,右边全为1,不难发现,二者相与结果为零,并且可以证明非二次幂的正整数n&(n-1)不会为0(这里就不花费篇章证明了).

nn-1n&(n-1)
100000001111110000000
100011100010100011
γ4. 找出唯一一个只出现一次的数(其他都是成对出现的)

a ^b ^b = a
如果给定我们一系列乱序的书页码(共n页),让我们从中找到,丢失的一页,这个性质便派上了用场,我们先枚举出1-n并相异或,再和输入的书页码相异或,这样,除了丢失的页码只出现一次,其他页码均出现两次,便得到了我们寻找的答案.

γ5. 枚举子集

这里笔者会用另外一篇文章来讲解,大家尽请期待~

posted @ 2020-12-02 15:31  沃特艾文儿  阅读(32)  评论(0)    收藏  举报  来源