C++ 与、或、异或、取反等运算

位运算符号优先级别从高到低:~ & ^ |;

其中~自由向左

1.&按位与

0 & 0 = 0, 0 & 1 = 0, 1 & 0 = 0, 1 & 1 = 1。
即同为1才为1;

C++输出一个数的二进制; 头文件#include<bitset>;
如果a为int,其二进制为:(bitset<32>(a))
如果其为long long,(bitset<64>(a))

2.| 按位或

0 | 0 = 0, 0 | 1 = 1, 1 | 0 = 1, 1 | 1 = 1
即有一个为1即为1;

3. 按位异或 ^

0 ^ 0 = 0, 0 ^ 1 = 1, 1 ^ 0 = 1, 1 ^ 1 = 0
即相同为0,不同为1;

int a=3;
a=a^0;//任何一个数与0异或都为原数;
int b=3;
a=a^b;;//一个数和另一个相等的数异域或为0;
int c=4;

  • 异或的另一个用处是交换元素不用申请变量;
int a;
a=a^b;
b=b^a; //b=b^a^b;
a=a^b;  //a=a^b^a^b^b;

4.按位取反~

哪些为0的位,结果是1,而哪些为1的位,结果是0。例如, ~7的结果为0xfff8。

5.<<左移

  • 左移:向左移动,右补0

移动n位,则相当于原数* 2^n;

6.>>右移

  • 向右移动,无符号左补零,有符号(整数左补0,负数左补零或1)

应用一:

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

  • 解题思路:
    首先:位运算中异或的性质:两个相同数字异或=0,一个数和0异或还是它本身。
    当只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。

依照这个思路,我们来看两个数(我们假设是AB)出现一次的数组。我们首先还是先异或,剩下的数字肯定是A、B异或的结果,这个结果的二进制中的1,表现的是A和B的不同的位。我们就取第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此,相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
    int xor1=0;
    for(int i=0;i<data.size();i++)
        xor1=xor1 ^ data[i];//求出不同的两个数的异域
    int index=1; //求出第一数所在区间,即将数组非为两个区间
     while((xor1 & index)==0)  //与结果为0,继续执行,不为零则退出
         index=index<<1;
     int r1=0;
     int r2=0;
      for(int i=0;i<data.size();i++)
      {
          if((data[i]&index)==0) //如果第i位不为1则,与r1异或
              r1=r1^data[i];
          else
              r2=r2^data[i];
      }
       *num1=r1;
       *num2=r2;
    }
};

应用二:求两数之和

  • 不用加减乘除完成两个数相加;

思路:
& 按位与运算:相同位的两个数字都为1,则为1;若有一个不为1,则为0。两个数相与,并左移一位:相当于求得进位
1&1=1 将1左移一位变成了10,相当于拿到了进位。
^ 按位异或运算:相同位置不同则为1,相同则为0。相当于每一位相加,而不考虑进位。
第一步 异或——无进位相加得result1 (a^b)
第二步 与+左移一位——求得进位result2 (a&b)<<1
第三步 result = result1 + result2即是结果
但问题在于,result1 + result2可能还有进位,因此result还要重复一二步这个过程。直到没有进位,异或的结果就是最终的结果为止
如 101 + 011 -> 110 + 1010 -> 1100 + 0100 -> 1000 + 1000 -> 0 (异或出现了0,返回上一次异或的结果)
最终得到的是1000 也就是5+3=8

class Solution {
public:
    int Add(int num1, int num2)
    {
       int temp;
       do{
           temp=num1^num2;
           num1=(num1 & num2)<<1;
           num2=temp;
       }while(num1!=0);
       return temp;
    }
};

求两数之差;

根据C++上两个互为相反数的int型数据的二进制结构关系——整数的相反数等于该数按位取反再加1;

int OppositeNumber(int n)
    return Add(~n, 1);
 int Subtract(int a, int b)
    return Add(a, OppositeNumber(b));
 }
  • 思路二:
    如果减数不为0,我们可以先把被减数和减数上同为1的位从两个数上去除。至于如何分离出值同为1的位,则可以通过求位与操作来做到;
    而把这些1分别中被减数和减数中去除,则可以通过按位异或来的操作来实现。
    经步骤1处理后,被减数和减数在对应的位上,将或者通为0,或者分别为0和1,却不会同为1。此时:
    如果对应位被减数=0,而减数=1,则所得结果对应位还是1,但此时须向前一位借1;
    == 即通过对减数左移一位得到需从临时结果中减去的借数。==
    于是,经过步骤2后,原来的减法变成了要求:临时结果 - 借数
    很明显,只要以临时结果为被减数,借数为减数,重复步骤1~3即可。
int Subtract(int a,int b)
{
while(b!=0)
{
	int sameBits=a&b;//计算出两个数同为1的位;
	a=a^sameBits;//分别求出a为1的位;对于的位b为0;
	b=b^sameBits;
	a=a|b; //不同位的求和;
	b=b<<1;//借位,右移动; 如011010;执行到00000循环退出
}
return a;
}

加减乘除的实现

猜你喜欢

转载自blog.csdn.net/qq_42698422/article/details/105633114
今日推荐