位运算
程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。 ——摘自某百科
常用的几种位运算
与 (&) \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;
}