位运算与进制基础
位运算符
1.在处理整形数值时,可以直接对组成整形数值的各个位进行操作。这意味着可以使用屏蔽技术获得整数中的各个位。
2.&(与)、|(或)、^(异或)、~(非/取反)。
3.>>和<<运算符将二进制位进行右移或者左移操作。
4.>>>运算符将用0填充高位;>>运算符用符号位填充高位,没有<<<运算符。
5.对于int型,1<<35与1<<3是相同的,而左边的操作数是long型时需对右侧操作数模64。
6.与:都为1结果为1;或:有一个为1结果为1,;异或:二者不同时结果为1。
小技巧
1.判断奇偶数:x&1=1则x是奇数,x&1=0则x是偶数。
2.获取二进制位是1还是0:x&某一个奇数之后再右移相应的位数。
3.交换两个整数变量的值。
4.不用判断语句,求整数的绝对值。
异或:可以理解为不进位加法:1+1=0,0+0=0,1+0=1。
性质
1.交换律可以交换运算因子的位置,结果不变。
2.结合律(即(a ^ b ) ^ c = = a ^ ( b ^ c ) )
3.对于任何数x,都有x ^ x = 0 , x ^ 0 = x ,同自己求异或为0,同0求异或为自己。
4.自反性A ^ B ^ B = A ^ 0 = A,连续和同一个因子做异或运算,最终结果为自己。
题解
题1:找出唯一成对的数
1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
思路
连续异或,消除重复。
代码
#include <iostream>
using namespace std;
int main()
{
int x=0,test[10]={1,2,3,4,5,6,7,8,9,7};
for (int i = 1; i <= 9; ++i) x=x^i;
for (int j = 0; j < 10; ++j) x=x^test[j];
cout<<x<<endl;
return 0;
}
题2:找出落单的那个数
一个数组里处理某一个数之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。
思路
连续异或,消除重复。
代码
#include <iostream>
using namespace std;
int main()
{
int x=0,test[11]={1,1,3,3,5,5,7,7,9,9,11};
for (int j = 0; j < 11; ++j) x=x^test[j];
cout<<x<<endl;
return 0;
}
题3:二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中的1的个数。
例:9的二进制表示为1001,有2位是1.
思路
1.整数x与1,然后将1循环左移32次;
2.整数x与1,然后将x循环右移32次;
3.x&(x-1)可以消掉最右边的1,直到x=0。
代码
#include <iostream>
using namespace std;
int main()
{
int x,n=1,ans=0;
cin>>x;
for (int i = 0; i < 32; ++i)
if (x&(n<<i)) ans++;
cout<<ans<<endl;
return 0;
}
#include <iostream>
using namespace std;
int main()
{
int x,ans=0;
cin>>x;
for (int i = 0; i < 32; ++i)
if ((x>>i)&1) ans++;
cout<<ans<<endl;
return 0;
}
#include <iostream>
using namespace std;
int main()
{
int x,ans=0;
cin>>x;
while (x)
{
x=x&(x-1);
ans++;
}
cout<<ans<<endl;
return 0;
}
题4:是不是2的整数次方
用一条语句判断一个整数是不是2的整数次方。
思路
2的整数次方说明x中只有一个1,x&(x-1)可以消掉最右边的1。
代码
#include <iostream>
using namespace std;
int main()
{
int x;
cin>>x;
if ((x&(x-1))==0) cout<<"yes"<<endl;
else cout<<"no"<<endl;
return 0;
}
题5:将整数的奇偶位互换
输入一个整数,将其二进制形式的奇偶位置数互换。
思路
一个数&(0101)×8得到的是它的所有奇数位数字,&(1010)×8得到的是它所有偶数位数字,然后分别左移和右移之后再异或一下,得到的就是奇偶位互换的数字。
代码
#include <iostream>
using namespace std;
int main()
{
int x;
cin>>x;
int ji=0x55555555,ou=0xaaaaaaaa;
int a=x&ji,b=x&ou,c=(a<<1)^(b>>1);
cout<<c<<endl;
return 0;
}
题6:0~1间浮点实数的二进制表示
给定一个介于0和1之间的实数,(如0.625),类型为double,打印它的二进制表示(0.101,因为小数点后的二进制分别表示0.5,0.25,0.123…)。
如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”
思路
浮点数转换为二进制的方式为乘2挪整。
代码
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
string s;
int len=0;
double x;
cin>>x;
while (x>0)
{
double num=x*2;
if (num>=1.0)
{
s+='1';
x=num-1;
}
else
{
s+='0';
x=num;
}
len++;
if (len>32)
{
cout<<"ERROR"<<endl;
return 0;
}
}
cout<<"0."<<s<<endl;
return 0;
}
题7:出现k次与出现1次
数组中只有一个数出现了1次,其它的数都出现了k次,请输出只出现了1次的数。
思路
k个相同的k进制数做不进位加法结果为0。