C++中位运算与应用


位运算是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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值