位运算------高效运算技巧

位运算基本操作:

  • & (与):都为1结果才为1
  • | (或):有一个为1结果就为1
  • ~ (非):0变成1,1变成0
  • ^(异或):两者不相同时才为1
  • (>>):右移运算符,将二进制位进行右移,右移一位相当于除以2
  • (<<):左移运算符,将二进制位进行左移,左移一位相当于乘2
  • (>>):将用符号位来填充高位
  • 对于int型,1<<35与1<<3是相同的(因为int32位需要对32取模),而左边的操作数是long型时需要对64取模

关于异或的一些性质:

  • 交换律,可任意交换因子的位置,结果不变
  • 结合律,即(a^ b)^ c == a ^ (b ^ c)
  • 对于任何数x,都有x^x=0,x ^0=x,同自己求异或等于0,同0求异或为自己
  • 自反性,A ^ B ^ B=A ^ 0 = A,连续和同一个因子做异或运算,最终结果为自己

利用位运算的一些小技巧:

1. 判断奇偶数

对于奇数来说,二进制的最后一位一定为1,而对于偶数来说,二进制的最后一位一定为0,所以判断一个数是奇数还是偶数直接和1进行与运算就可以了

#include <iostream>
using namespace std;
int main()
{
    
    
	int num;
	cin>>num;
	if(num&1)
		cout<<num<<"为奇数"<<endl;
	else
		cout<<num<<"为偶数"<<endl; 
		
	return 0;
 } 

2. 交换两个整数变量的值

给定两个整数A和B,要求交换两个数的值,常规方法就是再定义一个变量,然后进行交换,而最高效的方法仍是位运算。
A=A ^ B
B=A ^ B (此时B=(A ^ B)^B = A)
A=A ^ B (此时A= (A ^ B)^A = B)
由此,便完成了A和B的交换

#include <iostream>
using namespace std;
int main()
{
    
    
int a,b;
	cin>>a>>b;
	a=a^b;
	b=a^b;
	a=a^b;
	cout<<"a="<<a<<endl;
	cout<<"b="<<b<<endl;	
			
	return 0;
 } 

3. 获取二进制位是1还是0

例如给定一个数a,要求求出该数二进制第x位为1还是为0
此时直接将该数第k位与1进行与运算即可,也就是将1左移k-1位,然后和该数进行与运算,为1,则说明第x位为1,为0则说明第x位为0
num&(1<<k-1)

#include <iostream>
using namespace std;
int main()
{
    
    
int num,k;//k表示num的第k位 
	cin>>num>>k;
	if(num&(1<<k-1))
		cout<<num<<"的第"<<k<<"位为:1"<<endl;
	else
		cout<<num<<"的第"<<k<<"位为:0"<<endl;
			
	return 0;
 } 

4. 求整数的绝对值

如何不使用判断语句而求得一个数的绝对值,此时又用到了位运算
一、对于正数来说,它的符号位为0,因此对正数进行(带符号<<)右移31位,将得到全0,此时值为0。正数的绝对值是其本身
二、对于负数来说,他的符号位为1,因此对负数进行(带符号<<)右移31位,将得到全1,此时值为-1(因为计算机中是以补码来存储的)。负数的绝对值正好可以对其进行取反加一求得。

int t=(a>>31);
如果a是正数,则t为0,a为负数,则t为-1
int ans=(a^t)-t;
a为正数,绝对值就是其本身
a为负数时,a^t就是对a进行按位取反,t为-1,
减去t就是加上1,从而得到其绝对值。
#include <iostream>
using namespace std;
int main()
{
    
    
	int a;
	cin>>a;
	int t=(a>>31);
	int ans=(a^t)-t;
	cout<<ans<<endl; 
			
	return 0;
 } 

5. 求数字中1的个数

求一个数字的二进制中1的个数,有两种方法

(1)int型数字是32位的,因此for循环32次,将该数字和1左移k位进行与运算,得到的结果的1左移k位相等,则说明该数字第k位为1.

#include <iostream>
using namespace std;
int main()
{
    
    
int n;
	cin>>n;
	int cnt=0;
	for(int i=0;i<32;i++)
	{
    
    
		if((n&(1<<i))==(1<<i))
			cnt++;
	}
	cout<<cnt<<endl;
			
	return 0;
 } 

(2)假设这个数字为的二进制为10100,先将该数字减一,变为10011,(可以发现只要每减一次1,该数字最低位的1变为0,该位后边全变位1),将10011和10100进行与运算为10000,消去了一个1,因此可以记录消去1的个数直至该数字为0.

#include <iostream>
using namespace std;
int main()
{
    
    
	int n;
	cin>>n;
	int cnt=0;
	while(n)
	{
    
    
		n=(n-1)&n;
		cnt++;
	} 
	cout<<cnt<<endl;
	return 0;
 } 

猜你喜欢

转载自blog.csdn.net/weixin_45102820/article/details/113049036