【算法学习】位运算

任何信息在计算机中都是采用二进制表示的,数据在计算机中是以补码形式存储的,位运算就是直接对整数在内存中的二进制位进行运算。由于位运算直接对内存数据进行操作,不需要转换成十进制,因此处理速度非常快,在信息学竞赛中往往可以优化理论时间复杂度的系数。同时,一个整数的各个二进制位互不影响,利用位运算的一些技巧可以帮助我们简化程序代码。

C++提供了按位与(&)、按位或(I)、按位异或(^)、取反(~)、左移(<<)、右移(>>)这6种位运算符。这些运算符只能用于整型操作数,即只能用于带符号或无符号的char、short、int与long类型。

“a&b”是指将参加运算的两个整数a和b,按二进制位进行“与”运算。如果两个相应的二进制位数字都为1,则该位的结果为1;否则为0。这里的1可以理解为逻辑中的true,0可以理解为逻辑中的false。“按位与”其实与逻辑上“与”的运算规则一致。

//3-00000011

//5-00000101

 int a = 3;

 int b = 5;

int c = a & b;

cout << c<< endl; // 00000001

“a|b”是指将参加运算的两个整数a和b,按二进制位进行“或”运算。如果两个相应的二进制位数字有一个为1,则该位的结果为1否则为0。“按位或”其实与逻辑上“或”的运算规则一致。

// 48 - 00110000 
//15 - 0000111
 int a = 48;
int b = 15;
int c = a | b;
cout<< c<< endl; // 63 - 00111111

“a^b”是指将参加运算的两个整数a和b,按二进制位进行“异或”运算。如果两个相应的二进制位数字不相同,则该位的结果为1;否则为0。

a^0 = a         a^a = 0

// 52 - 00110100 
//15-00001111 
int a = 52;
int b = 15;
int c = a ^ b;

cout << c<< endl; // 59 - 00111011

“~a”是指将整数a的各个二进制位都取反,即1变为0,0变为1。“~”是一元运算符。

cout << ~9 << endl;
/*

9 - 00001001 
取反 - 11110110 补码
      11110101 反码
      10001010 原码

      最高位 1 表示负数 -10

*/

“a<<b”是指将整数a的各个二进制位左移b位,高位丢弃,低位用0补齐。需要注意的是b必须是非负整数。在高位没有1丢弃的情况下,a<<1相当于a*2。

char a = (143<<2);

printf("%d", a);

/*

143 - 10001111

左移2 - 1000111100 60

*/

“a>>b”是指将整数a的各个二进制位右移b位,低位丢弃。对于无符号数,高位补0。对于有符号数,某些机器将对左边空出的部分用符号位填补(即“算术移位”),而另一些机器则对左边空出的部分用0填补(即“逻辑移位”)。同样,b必须是非负整数。a>>1相当于a/2。

char a = (15 >> 2 );
printf( "%d",a);
/*
   15 - 00001111
  右移位2 - 00000011   3
*/


char a = (-15 >> 2 );
printf( "%d",a );
/*
  15 - 10001111
  反码 - 11110000
补码 - 11110001
右移2 - 1111110001
反码 - 11111011
原码 - 10000100  -4
*/

位运算符也可以与赋值运算符组成复合运算符。

例如a &=b相当于a=a&b,a<<=2相当于a=a<<2。

位运算符也是有优先级的,例如

  • “加减”高于“>>”“<<”
  • “~”“!”“++”“-”一致 ,高于“乘除”
  • “关系运算” 高于 “&” 高于 “^” 高于 “|”高于“&&”“||”

为了避免出错,增强程序的可读性,利于调试,建议在需要的地方添加括号来保证优先运算。比如1<<5-1,建议写成1<<(5-1),等价于1<<4。

例1:交换和取平均值

#include<iostream>
using namespace std;
int main()
{    //交换
   int x = 3,y = 9,z;
   x^= y;   //x = x^y;
   y^= x;   // y = y^x = (y ^ (x^y) ) =x;
   x^= y;   //x = x^y = (x^y)^x = y;
   cout << x << " " << y << endl;
   //取平均值
   z = (x&y) + ((x^y)>>1 );
   cout << z << endl;
  return 0;

}

 例2:整数幂

判断一个数n是不是2的整数幂,比如64=2^6,所以输出“yes”,而65 无法表示成2的整数幂形式,所以输出"no"。n在int 范围以内。

  • 【问题分析】
  • 我们考虑一个数如果是2的整数幂会有什么特殊性。观察发现64转换成二进制为0100000,只有一个位是1。将这个数减去1,就变成00111111的形式,我们将这2个数做按位与运算,发现结果为0。分析发现,如果一个数不能表示成2的整数幂形式,则以上过程的运算结果一定不为0。所以,可以利用位运算将算法的时间复杂度优化成O(1)。
#include<iostream>
using namespace std;
int main()
{
    int n;
    cin >> n;
    if (n&(n-1))
        cout << "no";
     else
        cout << "yes";
  return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值