位运算一些总结

1. 消除最后的一个“1”bit

x & ( x - 1 )

看上去很难理解,但是有很容易理解。要不先用几分钟思考一下?

 

比如:6 & ( 6 - 1 ) 就从 110 变为 100,消除了最后面的一个"1"bit,为什么呢?

  其实只需要考虑110 后面 的“10”就可以了,因为任何一个数后面都是10的结构(0可能有0~n),x > 0,为什么?

因为整数只有奇数和偶数。首先偶数最后一位必然为0,奇数则为1,这是也是我们判断奇偶数的原理。

所以了可以把任何一个正整数最后面的位看成10结构(0为0~n个)。

 

因此分两种情况,后面有没有0与n个"0"的情况。

第一种(没有0,也就是奇数情况):

  x & (x-1),x为奇数,这个很容易知道啊,x - 1 把二进制最后的1个去掉了,只是改动了一位,前面的没有动,因此消除了一个1bit

5 & (5-1) => 101 & (100) = 100 (黄色的地方没变化,变化的是第一位)

 

第二种情况(偶数,10结构):

这次使用一个大点的会容易理解,二进制数 n =  xxxx100000,前面的xxxx我们先忽略,因为我们不需要知道具体的值,只要符合10结构既可以,

因此 n - 1 = xxxx011111,这样看来 n & (n-1),就会把n中黄色的地方变为0,也就达到了消除最后一个1bit的效果

 

嗯,至少我先这么理解吧

 

2. 获取最后一个"1"bit

这次跟上面的其实有点相似的,只要思考思考就会想明白了。

同样我们也只要考虑最后面的几个bit就好了

  思路:有没有可以使用位运算来消除多余的位,只剩下最后那个1bit呢? & 可以试一试

比如一个正整数 n & ~n =0;这个会把所有的到消除了,不合适。

 

不妨假设 x 是n前面的bit,并且进行~运算会得到y

  因为每个大于0的整数都是10结构,比如:n & (~n) = x10000 & y01111 = 0,但是 n & (~n+1)  = x10000 & ( y01111 + 1 ) = x10000 & ( y10000 )  = 10000

思想就是把最后的 10结构保留原样,前面的就取反,这样进行&运算就可以得到最后的1bit了。

  我们来优化一下,~n + 1 可以变成什么?我们知道n是大于0的整数啊,~n + 1 不就是 -n的补码(使用补码存储与运算)?所以可以优化为: n & -n就可以了

 ~n + 1 = -n 
==> n & (~n+1) = n & -n
==> ~n = -(n+1)

 

3. 按区域取反

如果我想把某一个数n的某一个区域的bit取反会怎么样?

提示:使用异或运算,可以知道1遇到0会变1;如果1遇到1就会变0;0遇到啥都不会变;难懂这不就是取反吗

例子:A ^ B =  1010 ^ 1100 = 0100 。这个例子黄色部分bit就把A中某一部分的bit取反了。

接下来:就是让读者写出具有通用的代码了(让某一个数的n位到m位取反)

 

4. 位运算需要32位

需要注意的是,位运算在一些语言里面是基于32为整型。 比如PHP,Javascript等。

问:有人会问为什么JS也是要求32位呢,不是不区分浮点数,整型,更没有位数吗?

答:JS的确没有这些区分,但是位运算只能用于32位整型的。另外JS对于整型是有安全范围的,如果你使用过大的数(超过整型 Number.MAX_SAFE_INTEGER)就必须转为字符串,否则失真

 

类似的问题:

 * 某个区域设定固定的bit,比如 n 的4-7为设置为固定的bit不如全是1或者全是0,其他保持不变?

 

还有一些“著名”的题目:

single number I

single number II

single number III

3部曲,可以了解一下

 

以下是一个面试题的网站:

http://www.lintcode.com/zh-cn/problem/

 

posted @ 2017-10-01 11:46  XIAOLI的博客  阅读(453)  评论(0编辑  收藏  举报