位运算是C/C++中的基本运算,位运算允许程序员操作数据的某一特定位。
位运算
位运算由位运算操作符和操作数组成,不同的位运算操作符定义了不同的位运算。
| 操作符 | 示例 | 说明 |
|---|---|---|
| ~ | ~expr | 翻转expr的每一个位:1变0,0变1 |
| & | expr1&expr2 | 在每个位所在处,如果expr1和expr2都含有1,那么结果该位为1,否则为0 |
| | | expr1 | expr2 | 在每个位所在处,如果expr1和expr2都含有0,那么结果该位为0,否则为1 |
| ^ | expr1 ^ expr2 | 在每个位所在处,如果expr1和expr2不相同,那么结果该位为1,否则为0 |
| << | expr<<n | 将expr向左移动n位,移到外面的被丢弃,右边的位补0,因此左移n位相当于乘以2n |
| >> | expr>>n | 将expr向右移n位,移到外面的被丢弃,如果expr是无符号类型,则左边补0,否则,左边插入符号位的拷贝或者0(视具体实现而定) |
简单操作
操作第n位(从0开始算):
- 将expr的第n位设置为1: expr |= (1<<n);
- 将expr的第n位设置为0: expr &= (~(1<<n));
- 判断expr的第n位是否为1:bool b =expr & (1<<n);
- 翻转expr的第n位:expr ^=(1<<n);
复杂位操作
-
翻转最右侧1为0:
x&(x-1) -
获取最右侧1:
x&(-x) -
向右连续传播右侧1(尾部零全部转为1):
x|(x-1) -
判断是否为2的整数次幂:
(x&(x-1))==0(只有一位1,且非末尾) -
翻转右侧连续1为0:
((x|(x-1))+1)&x

-
判断是否为两个整数次幂之差:
((x|(x-1))+1)&x == 0(中间为连续的1,其他都为0)
位运算案例
交换整数
通过异或操作,可以方便地进行数值的交换。
template<class T>
void swapNumber(T& a,T& b)
{
a = a^b;
b = b^a;
a = a^b;
}
求二进制中1个数
输入一个整数N,输出其二进制表示中1的个数
int count1Bits(long num) {
int count = 0;
while (num) {
count++;
num &= (num - 1);
}
return count;
}
此处,使用了前面翻转最右侧1的方法,通过此方式,可以最快速的统计出1的个数。
字符串的组合
通过位操作,也可方便地完成字符串组合:
字符串的组合
找相同位1的整数
给定一个正整数N,求最小的、比N大的正整数M,使得M与N的二进制表示中有相同数目的1:
int nextN(int num) {
int last1Bit = num & (-num);
int carryLast1s = num + last1Bit;
int next = carryLast1s | ((num ^ carryLast1s) / last1Bit) >> 2;
return next;
}
说明:
num & (-num):获取最右侧的1,因-num是num的补码(全部取反后加1);其右侧(最末1与后面零)与num相同,其他相反;num + last1Bit:右侧1进位(最右侧连续1:左边1左移,其余为0);((num ^ carryLast1s) / last1Bit) >> 2:计算缺少的1,放在最右侧(低位);上一步加和时多了一个1,异或时为低位连续1与进位的1,所以需要右移两位去掉两个1;

被折叠的 条评论
为什么被折叠?



