300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 位运算技巧总结

位运算技巧总结

时间:2019-07-24 04:43:09

相关推荐

位运算技巧总结

概述

从现代计算机中所有的数据二进制的形式存储在设备中。即0、1两种状态,计算机对二进制数据进行的运算(+、-、*、/)都是叫位运算,即将符号位共同参与运算的运算。

口说无凭,举一个简单的例子来看下CPU是如何进行计算的,比如这行代码:

int a = 35;int b = 47;int c = a + b;

计算两个数的和,因为在计算机中都是以二进制来进行运算,所以上面我们所给的int变量会在机器内部先转换为二进制在进行相加:

35: 0 0 1 0 0 0 1 1

47: 0 0 1 0 1 1 1 1

————————————————————

82: 0 1 0 1 0 0 1 0

所以,相比在代码中直接使用(+、-、*、/)运算符,合理的运用位运算更能显著提高代码在机器上的执行效率。

性质

1.按位与运算符(&)

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

运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1;

即:两位同时为“1”,结果才为“1”,否则为0

例如:3&5 即 0000 0011& 0000 0101 = 00000001 因此,3&5的值得1。

另,负数按补码形式参加按位与运算

“与运算”的特殊用途:

(1)清零

如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。

(2)取一个数中指定位

方法:找一个数,对应X要取的位,该数的对应位为1,其余位为零,此数与X进行“与运算”可以得到X中的指定位。

例:设X=10101110,

取X的低4位,用 X & 0000 1111 = 00001110 即可得到;

还可用来取X的2、4、6位。

(3)判断奇偶

只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数。

2.按位或运算符(|)

参加运算的两个对象,按二进制位进行“或”运算。

运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1;

即 :参加运算的两个对象只要有一个为1,其值为1。

例如:3|5即 00000011 | 0000 0101 = 00000111 因此,3|5的值得7。

另,负数按补码形式参加按位或运算

“或运算”特殊作用:

(1)对一个数据的某些位置1

方法:找到一个数,对应X要置1的位,该数的对应位为1,其余位为零。此数与X相或可使X中的某些位置1。

例:将X=10100000的低4位置1 ,用X | 0000 1111 = 1010 1111即可得到。

3.异或运算符(^)

参加运算的两个数据,按二进制位进行“异或”运算。

运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;

即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。

“异或运算”的特殊作用:

(1)使特定位翻转,该数对应X要翻转的对应位为1其余位为零,此数与X对应位异或即可。

例:X=10101110,使X低4位翻转,用X ^00001111= 10100001即可得到。

(2)与0相异或,保留原值

如:X ^ 00000000 = 1010 1110。

下面重点说一下按位异或,异或其实就是不进位加法,如1+1=0,,0+0=0,1+0=1。

异或的几条性质:

1、交换律a ^ b = c===>a ^ c = b,b ^ c = a

2、结合律(a ^ b) ^ c == a ^ (b ^ c)

3、对于任何数x,都有x ^ x = 0,x ^ 0 = x

4、自反性: a ^ b ^ b = a ^ 0 = a;

异或运算最常见于多项式除法,不过它最重要的性质还是自反性:A XOR B XOR B = A,即对给定的数A,用同样的运算因子(B)作两次异或运算后仍得到A本身。这是一个神奇的性质,利用这个性质,可以获得许多有趣的应用。 例如,所有的程序教科书都会向初学者指出,要交换两个变量的值,必须要引入一个中间变量。但如果使用异或,就可以节约一个变量的存储空间: 设有A,B两个变量,存储的值分别为a,b,则以下三行表达式将互换他们的值 表达式 (值) :

a=a^b;

b=b^a;

a=a^b;

应用举例1:

(1) 1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现

一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空

间,能否设计一个算法实现?

解法一、显然已经有人提出了一个比较精彩的解法,将所有数加起来,减去1+2+…+1000的和。

这个算法已经足够完美了,相信出题者的标准答案也就是这个算法,唯一的问题是,如果数列过大,则可能会导致溢出。

解法二、异或就没有这个问题,并且性能更好。

将所有的数全部异或,得到的结果与1 ^ 2 ^ 3 ^ … ^ 1000的结果进行异或,得到的结果就是重复数。

4.左移运算符(<<)

将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。

例:a = a<< 2将a的二进制位左移2位,右补0,

左移1位后a = a *2;

若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2

5.右移运算符(>>)

将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。

操作数每右移一位,相当于该数除以2

例如:a = a>> 2 将a的二进制位右移2位,

左补0 or 补1得看被移数是正还是负

6.复合赋值运算符

位运算符与赋值运算符结合,组成新的复合赋值运算符,它们是:

运算规则:和前面讲的复合赋值运算符的运算规则相似。

7.不同长度的数据进行位运算

如果两个不同长度的数据进行位运算时,系统会将二者按右端对齐,然后进行位运算。

以“与”运算为例说明如下:我们知道在C语言中long型占4个字节,int型占2个字节,如果一个long型数据与一个int型数据进行“与”运算,右端对齐后,左边不足的位依下面三种情况补足,

(1)如果整型数据为正数,左边补16个0。

(2)如果整型数据为负数,左边补16个1。

(3)如果整形数据为无符号数,左边也补16个0。

如:long a=123;int b=1;计算a& b。

如:long a=123;int b=-1;计算a& b。

如:long a=123;unsigned intb=1;计算a & b。

补充学习 链接

枚举一个无重复字符串所有子集的技巧

将该字符串转成二进制数组表示

例如: 用二进制数组表示单词中那些字母出现(1表示),那些没出现(0表示),找出该单词的所有子集。

ace 对应二进制 int origin = 21 (二进制10101),包含的子集(n代表子集,初始 n = origin)有:

ace 10101ce 10100ae 10001ac 00101e 10000c 00100a 00001

遍历核心代码:n = (n - 1) & origin;// n-1 AND puzzleBit,生成一个puzzleBit的新的子集合

可以自己手动推算一下,是对的,n刚好遍历完所有情况

找map中 存在的 字符串str = ace(必含有首字母a)子集的个数

int first = 1 << (str[0] - 'a');while (n > 0) {// 遍历origin 的所有字母组合,当n=0时终止遍历// 按位都是1才为1,否则为0,即n这个组合包含origin 的首字母// 而且n这个组合在map中有值,即有单词长n这样,值累加给res[i]if ((n & first) != 0 && map[n] > 0) {res[i] += map[n];}// n-1 AND puzzleBit,生成一个puzzleBit的新的子集合n = (n - 1) & puzzleBit;}

寻找数字x二进制表示中 1的个数

为了表述简洁,下文用「一比特数」表示二进制表示中的 11 的数目。

每个 int 型的数都可以用 32 位二进制数表示,只要遍历其二进制表示的每一位即可得到 1 的数目。

利用位运算的技巧,可以在一定程度上提升计算速度。按位与运算(&)的一个性质是:对于任意整数 x,

令 x=x&(x−1),该运算将 x 的二进制表示的最后一个 1 变成 0。因此,对 x 重复该操作,直到 x 变成 0,则操作次数即为 x 的「一比特数」

另外,部分编程语言有相应的内置函数,例如 Java 的 \Integer.bitCount,C++ 的 __builtin_popcount,Go 的 bits.OnesCount 等,读者可以自行尝试。

int countOnes(int x) {int ones = 0;while (x > 0) {x &= (x - 1);ones++;}return ones;}

常用位运算公式

a >> b & 1 代表检查 a 的第 b 位是否为 1,有两种可能性 0 或者 1a += 1 << b 代表将 a 的第 b 位设置为 1 (当第 b 位为 0 的时候适用)

如不想写对第 b 位为 0 的前置判断,a += 1 << b 也可以改成a |= 1 << b

PS. 1 的二进制就是最低位为 1,其他位为 0 哦;>>运算符 优先级 高于 &运算符哦

以上两个操作在位运算中使用频率超高,建议都加深理解。

题目示例

相关位运算题目详见此篇 博客

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。