题目一:二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。
例如:9的二进制表示为1001,有2位是1。
题目分析:
首先题目给我们的是一个整数,一个一般的整数大多是32位,其次在这里我们需要用之前的<< 和>>运算符对整数的二进制的每一位求与运算,从与运算的结果中,知道整数中1的个数。
方法一代码如下:
#include <stdio.h>
int main()
{
int i,j,k=0;
scanf("%d",&j);
for(i=0;i<32;i++)
{
if((j&(1<<i))==(1<<i))//前面的与运算的结果是1,刚好等于1移动到对应位置的值
k=k+1;
}
printf("%d",k);
getch();
return 0;
}
运行效果:
方法二代码如下:
方法二的原理和一差不多,不同之处在于,方法二是移动了数字就不是1;
#include <stdio.h>
int main()
{
int i,j,k=0;
scanf("%d",&j);
for(i=0;i<32;i++)
{
if(((j>>i)&1)==1)//前面的与运算的结果是1,刚好等于1
k=k+1;
}
printf("%d",k);
getch();
return 0;
}
运行效果:
方法三代码如下:
方法三的解题原理如下:通过每一次的减1得到的结果再和上一次的数做与运算,就能消去原本的数最后的一个1,重复直到最后最开始的数为0,这时减去1的次数就是原来的数字的二进制有多少个1。
#include <stdio.h>
int main()
{
int count=0,j;
scanf("%d",&j);
while(j!=0)
{
j=j&(j-1);
count++;
}
printf("%d",count);
getch();
return 0;
}
运行效果:
题目二:将整数的奇偶位互换
题目分析:如果之前没有习惯位运算,在这里有一种做法就是将输入的数变成二进制,然后用字符串数组将二进制数存在里面,然后对下标为i=2k(k属于自然数)的元素取出来放,在一个新数组的奇数位;将下标为i=2k+1(k属于自然数)的元素取出来,放在新数组的偶数位。
现在我们用为运算来解决,我们可以用0xaaaaaaaa(16进制表示1010 1010 ......)与原数做与运算,取出原数的偶数位上的数字,然后可以用0x55555555(16进制表示0101 0101......)与原数做与运算,取出原数的奇数位上的数字,然后分别将取出的数右移和左移一位,再进行异或运算,得到的结果就是我们想要的结果。
代码如下:
#include <stdio.h>
int main()
{
int number,o,j;
scanf("%d",&number);
o=number&0xaaaaaaaa;
j=number&0x55555555;
printf("%d",(o>>1)^(j<<1));
getch();
return 0;
}
运行结果:
题目三:出现k次与出现1次
数组中只有一个数出现了1次,其他的数都出现了k次,请输出只出现了1次的数。
题目分析:这道题其实可以直接用暴力解法,把每一个数出现的次数记录下来,然后选出次数为1的数字,但是在这里我们采用位运算相关的知识来进行讲解。首先这里要给大家补充一个知识点:k个相同的k进制数做不进位加法,结果为0,这句话是解题的核心。当我们将题目数组中数字全部转化为他们对应出现k次数的进制,然后进行不进位相加,这个时候数组中出现了k次的相同数字得到的结果将会是0,剩下的数字就是只出现了一次的数字,然后我们再用进制转换,将其转换为10进制,这样出现一次的数字就出来了。
示例代码如下:
#include<stdio.h>
#include<math.h>
int main(){
int k=3;
int b[32] = {0};
int i,j;
int a[10]={11,11,11,22,22,22,33,33,33,44};
for(i=0;i<10;i++){
int j = 0;
while(a[i]!=0){
b[j]=b[j]+a[i]%k;
b[j]=b[j]%k;
a[i]=a[i]/k;
j++;
}
}
int m=0;
for(i=0;i<32;i++){
m=m+b[i]*pow(k,i);
}
printf("%d",m);
return 0;
}
运行效果: