1.十进制转化为二进制(编译器为32进制)
#include<iostream>
using namespace std;
int main()
{
int m,number ,s[32];
cin>>number;
for(int i=1;i<=32;i++)
s[i-1]=number>>(i-1)&1;
for(int i=31;i>=0;i--)
cout<<s[i]<<' ';
return 0;
}
2.输入二进制以十进制显示
#include<iostream>
using namespace std;
int show10(char *c)
{
int num=0;
for(int i=0;i<=31;i++)
num=(num<<1)+c[i];
return num;
}
int main()
{
int x;
char c[32];//以字符形式输入32位的二进制
for(int i=0;i<=31;i++)
cin>>c[i];
for(int i=0;i<=31;i++)//字符转换为数字
c[i]=c[i]-'0';
cout<<show10(c)<<endl;
return 0;
}
按位与运算符(&):参数运算的两个运算量,如果两个相应的为都为1,则该位的结果值为1,否则为0.即
0&0=0;0&1=0;1&0=0;1&1=1;
按位运算通常用于二进制取位操作,例如一个数and1的结果就是取二进制的最末位。这可以用来判断一个正整数的奇偶,二进制的最末为0,表示该数为偶数,最末尾为1表示该数为奇数。
//判断奇偶性
#include<iostream>
using namespace std;
int main()
{
int x;
cin>>x;
if((x&1)==0)//注意位运算的优先级很低,所以必须加括号
cout<<x<<"是欧树"<<endl;
else
cout<<x<<"是奇数"<<endl;
return 0;
}
如果A,B为整数,实际上可看成长度为32的二进制数各个位做上述操作。例如当A=10(二进制为1010),B=12(二进制为1100),A&B=8 (1010&1100=1000)
#include<iostream>
using namespace std;
int main()
{
int a=10;
int b=12;
int c=a&b;
cout<<c<<endl;//输出结果
return 0;
}
按位或运算符(|): 两个相应位置中只要有一个为1,该位的结果值就为1.即:0|0=0;0|1=1;1|1=1;
按位运算通常用于二进制特定位上的无条件赋值,例如一个数or1的结果就是把二进制最末尾强行变成1.如果需要把二进制最末尾变成0,
对这个数or1之后再减1就可以了,其实际意义就是把这个数强行变成最接近的偶数。
#include<iostream>
using namespace std;
int main()
{
int x;
cin>>x;
if(x&1==1)
x=(x|1)-1;//注意按位运算的优先级很低,所以必须加括号
cout<<x<<"是最接近原数的偶数"<<endl;
return 0;
}
如果A,B为整数,实际上可以看成长度32的二进制数各个位做上述操作。例如当A=10(二进制为1010),B=12(二进制为1100)时,A|B=14(1010|1100=1110).
//两个二进制按位或
#include<iostream>
using namespace std;
int main()
{
int a=10;
int b=12;
int c=a|b;
cout<<c<<endl;//输出结果为14
return 0;
}
异或运算符(^):它的规则是参加运算的两个相应位同号,则结果为0,异号则结果1,x or r的直观意思就是“是不是不一样“。即:
0^0=0; 0 ^ 0= 1; 1 ^ 0=1; 1 ^ 1= 0;
//两个整数异或
#include<iostream>
using namespace std;
int main()
{
int a=10;
int b=12;
int c=a^b;
cout<<c<<endl;//输出结果为6
return 0;
}
x or 运算的逆运算是他本身,也就是说两次异或同一个数最后结果不变,即(a xor b)xor b= a.
//异或加密
#include<iostream>
using namespace std;
int main()
{
int x=1314520;
x=x^123475678;
cout<<"加密后的值为:"<<x<<endl;
x=x^12345678;
cout<<"解密后的值为:"<<x<<endl;
return 0;
}
异或的另一个作用就是交换两个整数,不用临时变量,但是这种方法经检查有一定的局限性,例如不能写在函数里,否则结果会出错,例如快速排序里的swap函数如这样写:
a=a^b;
b=a^b;
a=a^b;
会出现a和b代表相同的元素交换出0的情况。
所以平时让两束交换值得情况还是采用原始的方法较好。(并且该操作并没有明显的时间优势)
#include<iostream>
using namespace std;
int main()
{
int a=123;
int b=789;
a=a^b;
b=a^b
a=a^b;
cout<<a<<b<<endl;//输出结果为789 123
return 0;
}
有一组连续的数字,从1到n排列,中间丢失了一个数字,顺序也被打乱,放在一个n-1的数组里,请使用位运算的方法找出丢失的数字
分析:由于1 ^ 1= 0; 2 ^ 2=0; n ^ n=0;因此将n-1个数异或后再来异或一下1,2,……,n。那么最终答案就肯定是迷失的数字k^(1 ^ 1) ^ (2 ^ 2) ^ (3 ^ 3) …… ^ (n ^ n)。其时间复杂度为线性。
//缺失的数字
#include<iostream>
using namespace std;
int find(int a[],int size)
{
int number = 0;
for(int i=0;i<size;i++)
number=number^(i+1)^a[i];//a[10]数组与1~10异或
number^=(size+1);//与11相异或就可以得到
return number;
}
int main()
{
int a[10]={1,2,4,5,6,7,8,9,10,11};
cout<<find(a,10)<<endl;
return 0;
}
扩展思考:如果有两个数迷失了呢?
用1 ^ 2 ^ 3 ^ …… ^ n的结果诸葛异或当前输入数据,得到x ^ y。由于x与y不相同,所以x ^ y的结果中至少有一位是1.我们根据这一位的不同(0或1)将输入数据以及1,2,3,……,n。分成两堆进行异或即可得到x和y。(理解不了)
与此类似的,N个数,N大到只有保证程序,读入不超时,其中就仅有一个数出现了奇数次,找出这个数的方法是读一个数异或一个,出现偶数个的垦丁抵消了,剩下来的就是那个数了。
//缺失两个数字
#include<iostream>
using namespace std;
int j=1;
int find(int a[],int start,int length)
{
int number=0;
for(int i=start;i<=start+length;i++)
{
number=number^(i+j)^a[i];
}
number^=(Length+j+1+start);
j++;
return number;
}
int main()
{
int a[10]={1,2,4,5,6,7,9,10,11,12};
cout<<find(a,0,4)<<endl;//此处不能用cout<<find(a,0,4)<<find(a,5,0)<<endl;会出错
cout<<find(a,5,4)<<endl;
return 0;
}
取反运算符(~),用来对一个二进制数按位取反,即将0变1,1变0.例如对二进制数1取反即: ~ 1=0;
例如一个整数a为10,则~a=-11,这里符号也是取反的因此变为负数。
使用取反运算符的时候要格外小心,需要注意整数类型有没有符号。有符号的整数与无符号的整数取反结果是不一样的
。对于有符号类型,取反后效果就是把这个数在数轴上的位置“对折翻着到另一边去“,因为无符号类型的数是用
0X000000000到0xFFFFFFFFFFF依次表示的。
而对于有符号的类型,取反后最高位的变化导致了正负颠倒,又因为负数存储使用补码,所以效果就变为了-a-1.这与上界没有任何关系。
#include<iostream>
using namespace std;
int main()
{
unsigned short a=100;
a=~a;
cout<<a<<endl;
return 0;
}
左移运算符(<<):A<<B,表示A的所有二进制为整体向左移动B位,后面B位用0补充,与此相对应的为右移符号(>>)。
通常认为a<<1比a*2更快,因为前者是更底层一些操作。因此程序中乘以2的操作尽量用左移一位来代替。
标记:1.最大公约数的二进制算法用除以2的操作来代替慢的出奇的mod运算,效率可以提高60%。
2.数独游戏 需要统计每一行,每一列和每一个小的九宫格里面已经有了那些数了,此时我们可以用27个小于29的整数进行记录。例如,一个只填了2和5的小九宫格就用数字18表示(二进制为000010010),而某一行的状态为511(即二进制111111111)则表示这一行已经填满了。需要改变状态时我们不需要把这个数转成二进制修改后再转回去,而是直接进行位操作。在搜索时,把状态表示成整数可以更好地进行判重等操作。这是在搜索中使用位运算加速的经典例子。
表列举了一些常见的二进制的变换操作。
| 功能 | 示例 | 位运算 |
|---|---|---|
| 去掉最后一位 | 101101->10110 | x>>1 |
| 在最后加一个0 | 101101->1011010 | x<<1 |
| 在最后加一个1 | 101101->1011011 | (x<<1)+1 |
| 把最后一位变成1 | 101100->101101 | x \ 1 |
| 把最后一位变成0 | 101101->101100 | (x\1)-1 |
| 最后一位取反 | 101101->101100 | x^1 |
| 把右数第k位变成1 | 101001->101101,k=3 | x(1<<(k-1)) |
| 把右数第k位变成0 | ||
| 右数第k位取反 | 101001->101101,k=3 | x^(1<<(k-1)) |
| 取末三位 | 1101101->101 | x&7 |
//最朴素程序
#include<iostream>
using namespace std;
int main()
{
int i,x,c=0;
cin>>x;
for(i=1;i<=32;i++)
{
c=c+(x&1);//判断最末尾是0还是1
x=x>>1;//去掉最右一位
}
cout<<(c&1);//判断奇偶性,是奇数输出1偶数输出0.
return 0;
}
//位运算
#include<iostream>
using namespace std;
int main()
{
int x;
cin>>x;
x=x^(x>>1);
x=x^(x>>2);
x=x^(x>>4);
x=x^(x>>16);
cout<<(x&1)<<endl;
return 0;
}
上式可以表述为如下结果。
#include<iostream>
using namespace std;
int main()
{
int x;
int k=1;
int temp;
cin>>x;
for(int i=0;i<5;i++)
{
temp=t>>K;
x^=temp;
K*=2;
}
cout<<(x&1)<<endl;
return 0;
}
得到一个新的二进制结果数,其中右起第i位置上的表示原数中第i和i+1位上有奇数个1还是偶数个1.比如,最右边那个0表示原数末两位有偶数个1,右起第三个位上的1就表示原数的第三个和第四个位上有奇数个1.
//用位运算来取一个整数的绝对值
#include<iostream>
using namespace std;
int Abs(int x)
{
int y;
y=x>>31;
return (x^y)-y;
}
int main()
{
int x;
cin>>x;
cout<<Abs(x);
return 0;
}
利用二进制运算直接将十进制转化为相应的二进制。
#include<iostream>
using namespace std;
int main()
{
int number,i,j,m,ok=0;
int s[50];
memset(s,0,sizeof(s));//将数组所有元素初始化为0
cin>>number;
for(i=1;i<=32;i++)//32位的编译器
{
m=number>>(i-1)&1;//将每一位移到最右端与1进行运算
s[i]=m;
}
for(i=49;i>=1;i--)//倒序输出
{
if(ok==0&&s[i]==1)//忽略前面的0
ok=1;
if(ok==1)
cout<<s[i];
}
return 0;
}
将十进制数转化为相应的十六进制数。
十进制转化为十六进制
#include<iostream>
#include<string>
using namespace std;
int main()
{
int number,m,i;
string s;
cin>>number;
for(i=0;i<7;i++)
{
m=number>>(i*4)&15;//先移动四位再与15(去后四位)
if(m<10)
x=char(m+48)+s;//处理数字,注意相加的前后顺序
else
s=char(55+m)+s;//处理字母
}
while(s[0]=='0')
s.erase(0,1);//删除前导0
cout<<s;
return 0;
}
//标记
//程序名称:十进制数转化为N进制数
//程序名称:采用除N取余方式,注意特殊数据0的处理
#include<iostream>
using namespace std;
string fun(int x,int n)
{
const string a="0123456789ABCDEF";
string s="";
if(x==0)
return "0";
while(x>0)
{
s=a[x%n]+s;
x=x/n;
}
return s;
}
int main()
{
int x,n;
cin>>x>>n;
cout<<fun(x,n)<<endl;
return 0;
}
十进制小数转化为N进制数。转换的方法是“乘N顺序取整“
输入样例:x,n=1065.8125 8
输出样例:2051.64
#include<iostream>
using namespace std;
double x;
int n;
string s;
void fun(double x,int n,int m)
{
const string a="0123456789ABCDEF";
int u;
s='.';
while(x>0&&m>0)
{
m--;//可用小数位数减1
x=x*n;
s=s+a[int(x)];//去余数依次放后面
x=x-int(x);//取X的小数部分
}
}
int main()
{
cin>>x>>n;
if(x<1)
fun(x,n,20);
cout<<s;
return 0;
}
N进制转化为十进制
/*
程序名:N进制转为十进制
*/
#include<iostream>
using namespace std;
int fun(int n,string s)
{
int i,t=0;
for(i=0;i<s.size();i++)
{
if(s[i]>='0'&&s[i]<='9')
t=t*n+s[i]-48;
else if(s[i]>='A'&&s[i]<='F')//十六进制
t=t*n+s[i]-55;
else if(s[i]>'a'&&s[i]<='f')
t=t*n+s[i]-87;
}
return t;
}
int main()
{
int n;
string str;
cin>>n;
cin>>str;
cout<<fun(n,str);
return 0;
}
N进制小数转换为十进制。转换的基本算法还是“乘权求和“,只是程序有所不同,例如十进制数0.26345如果用2/10+6/100+3/1000+4/10000+5/100000计算的话,计算次数过多,而如果用秦九昭算数计算的话只要左五次除法即可。
//N进制小数转化为十进制
#include<iostream>
using namespace std;
double x,t,j;
double fun(double n,string s)
{
int i;
for(i=s.size();i>=1;i--)
{
if(s[i]>='0'&&s[i]<='9')
t=t/n+s[i]-48;
else if(s[i]>='A'&&s[i]<='F')
t=t/n+s[i]-55;
else if(s[i]>='a'&&s[i]<='f')
t=t/n+s[i]-97;
j=t/n;
}
return j;
}
int main()
{
int n;
string s;
cin>>n;
cin>>s;
cout<<fun(n,s);
return 0;
}
【题目描述】
N进制加法,N进制数加法运算问题,即从键盘输入一个小于37的正整数N,再输入复合要求的两个N进制数,求两者之和,数出结果仍为N进制数。
//进制数加法
#include<iostream>
using namespace std;
int main()
{
string a,b,w;
int x[100],y[100];
int i,k,N;
cin>>N;
for(i=0;i<=n-1;i++)
{
if(i<10)
w=w+char(i+48);//数字的处理
else
w=w+char(55+i);//字母处理
}
cin>>a>>b;
while(a.length()<b.length())
a='0'+a;
while(b.length()<a.length())
b='0'+b;
a='0'+a;//前面多加一位,用于进位
b='0'+b;
for(i=a.length()-1;i>=0;i--)
{
x[i]=w.find(a[i],0);//查找a[i]在W中的位置获得真实的数字
y[i]=w.find(b[i],0);//转换到x,y数组中准备相加
}
for(i=a.length()-1;i>=0;i--)//进位加法
{
x[i]=x[i]=y[i];//jn
if(x[i]>=N)
{
k=i;
while(x[k]>=N)
{
x[k]=x[k]-N;
x[k-1]++;
k--;
}
}
for(i=a.lenght()-1;i>=0;i--)
a[i]=w[x[i]];//转换为N进制数,a即是加法又是总数
while(a[0]=='0')
a.erase(0,1);//删除前导0
cout<<a<<endl;
return 0;
}
}
【逃跑路线】
假设向上走用1表示,向右走用0表示。请编程统计出修罗王从A地到B地有多少种走法,打印出每一种走法:如0010101.
可以看要从A到达B,不管怎么走都必须向右走4段,向上走3段,也就是说在7位的二进制中所有由4个0和3个1构成的二进制的个数,由于符合条件的最小二进制数为0000111(即十进制7),最大二进制数:1110000(即十进制数112)。因此只要将7~112都转化为二进制数,找出7位二进制中由4个0和3个1构成的二进制数即为所示的走法方案。
#include<iostream>
using namespace std;
int i,j,t,a;
int len,r,r0,r1;
string b,jg;
int main()
{
t=0;
for(i=7;i<=112;i++)
{
a=i,r0=0,r1=0,jg="";
do
{
r=a%2;
if(r==1)
r1++,jg='1'+jg;
else
r0++,jg='0'+jg;
a/=2;
}while(a!=0);
len=ji.size();
if(len<7)
for(j=0;j<7-len;j++)
jg='0'+jg;
if(r1==3&&r0+7-len==4)
{
t+=1;
cout<<jg;
for(j=8;j<=10;j++)
cout<<' ';
}
}
cout<<"\n";
cout<<"t="<<t<<"\n";
getchar();
getchar();
return 0;
}