位运算详解

位运算

程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。 ——摘自某百科

常用的几种位运算

与 (&) \and
当两个数在二进制下对应位数上均为 11 时,得到的结果为 11.
或 (|) \or
当两个数在二进制下对应位数上有一个为 11 时,得到的结果为 11.
异或 (^) \xor
当两个数在二进制下对应位数上不相同时,得到的结果为 11.
左移 (<<)
将一个数在二进制下整体向左移位
右移 (>>)
将一个数在二进制下整体向右移位且最高位补0.
举个栗子:
7=(00000111)2​
11=(00001011)2​
7 and 11=(00000011)2​=3
7 or 11=(00001111)2​=15
7 xor 11=(00001100)2​=12
7<<1=(00001110)2​=14
7>>1=(00000011)2​=3
通常情况下,左移一位表示将这个数乘以2,右移一位表示将这个数除以2,向下取整.

1 基本概念

1.1 符号

异或是一种二进制的位运算,符号以 XOR 或 ^ 表示。

1.2 运算规则

相同为0,不同为1,即

1 ^ 1 = 0

0 ^ 0 = 0

1 ^ 0 = 1

由运算规则可知,任何二进制数与零异或,都会等于其本身,即 A ^ 0 = A。

1.3 异或性质

(1)交换律: A ^ B = B ^ A

(2)结合律: ( A ^ B ) ^ C = A ^ ( B ^ C )

(3)自反性: A ^ B ^ B = A (由结合律可推: A ^ B ^ B = A ^ ( B ^ B ) = A ^ 0 = A

异或应用

1 变量交换

2排除偶次重复
1.示例:在一个整数数组中,仅存在一个不重复的数字, 其余数字均出现两次(或偶数次),找出不重复数字。
解法:求数组异或和
2.示例:在一个已知区间的数组,仅存在一个重复的数,找重复的数
解法:求区间异或和+数组异或和

#include<bits/stdc++.h>
using namespace std;

int main()
{
 srand(time(NULL));
 int a=rand()%10+1;
 int n[100];
 for(int i=0;i<10;i++){
  n[i]=i+1;
 }
 n[10]=a;
 int ans=0;
 cout<<a<<endl;
 for(int i=1;i<=10;i++){
  ans^=i;
 }
 for(int i=0;i<=10;i++){
  ans^=n[i];
 }
 cout<<ans<<endl;
 
}

移位和&^应用

1. 计算一个数的二进制中有多少个1
10----->1010
1.每一位和2取&若值为1则该处有1
2.将该数与1不断右移比较取&查看该位是否有1
3.不断和该数的减一取&直到该数为0查看进行了几次
原理10----->1010&减一---->1001得到1000
2. 计算是否为2的整数次方
N&(N-1)==0
3. 奇偶位互换
ou=a&(…1010)得到偶数位置
ji=a&(…0101)得到奇数位置
(ou>>1)^(ji<<1)得到奇偶互换的数

#include<bits/stdc++.h>
using namespace std;

int main()
{
	int a,ans=0;
	cin>>a;
	for(int i=0;i<32;i++){
		if((a>>i)&1){
			ans++;
		}
	}
	cout<<ans<<endl;
	ans=0;
	for(int i=0;i<32;i++){
		if((a&1<<i)&1<<i)
		ans++;
	}
	cout<<ans<<endl;
	ans=0;
	int b=a;
	while(b!=0){
		b=(b-1)&b;
		ans++;
	}
	cout<<ans<<endl;
	if(!(a&(a-1)))
	puts("yes");
	else
	puts("no");
	int ou=a&0xaaaaaaaa;
	int ji=a&0x55555555;
	cout<<((ou>>1)^(ji<<1))<<endl;	
	return 0;
}

小数二进制

乘2挪整
0.625 ---->1.250------>0.250---->0.1
0.250 ---->0.500------>0.500---->0.10
0.500 ----->1.000----->0.000---->0.101

#include<bits/stdc++.h>
using namespace std;

int main()
{
	double a;
	string s="0."; 
	cin>>a;
	while(a>0){
		double num=2*a;
		if(num>=1){
			s.append("1");
			a=num-1;
		}
		else{
			s.append("0");
			a=num;
		}
		if(s.length()>34){
			{
				puts("ERROR");
			return 0;
			}
		
		}
	}
	cout<<s<<endl;
	return 0;
}

出现k次与出现1次

两个相同的二进制数做不进位加法,结果为0。
十个个相同的十进制数做不进位加法,结果为0。
K个相同的K进制数做不进位加法,结果为0。
当然这里用map更好

#include<bits/stdc++.h>
using namespace std;
map<int,int>m;
int main()
{
	int n[100]={1,1,1,2,2,2,5,7,7,7};
	for(int i=0;i<10;i++){
		m[n[i]]++;
	}
	cout<<m.size()<<endl;
	  map<int, int>::reverse_iterator   iter;
     for(iter = m.rbegin(); iter != m.rend(); iter++){
          cout<<iter->first<<" "<<iter->second<<endl;
     }
//      map<int, int>::iterator iter;
//		for(iter=m.begin();iter!=m.end();iter++)
//		{
//			cout<<iter->first<<" "<<iter->second<<endl;
//			if(iter->second==1) cout<<"找到了"<<iter->first<<endl;
//		}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值