关于二进制位操作的一些面试题
题目1:
1、不能创建临时变量,实现两个数的交换。
2、思路
1)常规方法,创建临时变量(很简单)
int main()
{
int a = 1;
int b = 2;
printf("交换前:a = %d b = %d\n", a, b);
int tmp = 0;
tmp = a;
a = b;
b = tmp;
printf("交换后:a = %d b = %d\n", a, b);
return 0;
}
2)利用加法求和来做(缺点:在数据溢出时,结果错误)
int main()
{
int a = 1;
int b = 2;
printf("交换前:a = %d b = %d\n", a, b);
a = a + b;
b = a - b;
a = a - b;
printf("交换后:a = %d b = %d\n", a, b);
return 0;
}
3)**第三种方法是:利用异或来做,这个是很多人想不到的,这不一定,它的原理是:相同为0,相异为1。可以得出 a^a = 0 a^0 = a;**靠这两个关系式来做!
int main()
{
int a = 1;
int b = 2;
printf("交换前:a = %d b = %d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后:a = %d b = %d\n", a, b);
return 0;
}
题目2:
3、求一个整数存储在内存中的二进制中1的个数
*突然想到一个问题,特别重要!!!
int a = 1;(在内存中补码存储)
int b =-1;(在内存中补码存储)
unsigned int c = 10;
unsigned int d = -10;这两个在内存中怎么存储呢?验证一下!!!
数据在内存中怎样存储的跟数据类型无关,跟它本身是正数还是负数有关,在printf通过格式控制打印的时候,这时候是要求打印的什么数,根据要求转换在内存中看到的数!!!
有了这些基础来搞这道题!!!
4、思路
1)既然它是求得在内存中的二进制数的1的个数,那么可以把这个数a%2判断是不是1,a/2去掉一位,就可以计算,但是有个问题,你想一下,如果这个数是正数,符号位是0,不是1,自然可以这样算,如果是负数呢?就不能这样算了,一个是符号位是1,需要统计进去,还有一个问题,与2的余数就不是0或1了,不能计算,基于上面的这几种情况,即使是正数,也不合适,只是结果对了,因为在正数中,把符号位没有统计(虽然它是0,统计不统计一样),负数压根不合适,这种情况的解决办法就是转成无符号数来搞,就可以了,因为重要一个确定了,那么在内存中存的形式是一定的,当转成无符号数时,二进制全部是数值位,就可以这样计算了!!!这种方法没有你想象的那么简单!!!
int CountOnebit(unsigned int num)
{
int count = 0;
while (num)
{
if (num%2 == 1) {
count++;
}
num /= 2;
}
return count;
}
int main()
{
int nums = CountOnebit(-10);
printf("%d\n", nums);
return 0;
}
2)第二种方法是用&操作符来做,这个&(按位操作符)直接面对的是二进制,没有那么多弯弯绕绕!可以直接做,右移一位,判断一位!
int CountOnebit(unsigned int num)
{
int count = 0;
for (int i = 0; i < 32; i++)
{
int a = num>> i;
//1
//00000000 00000000 0000000 0000001 1的特殊性来做
if (a & 1 == 1)
{
count++;
}
}
return count;
}
int main()
{
int nums = CountOnebit(-10);
printf("%d\n", nums);
return 0;
}
3)第三种方法跟第二种差不多,因为二进制只有0和1,你想一下,a = -10,b = -10-1,在a的基础上-1,是不是对应的补码差1,那么a和b对应的二进制的最后1位或2位肯定不一样,则可以统计&操作符,来使最后的一位或两位成为0,则去除了一个1,这样通过不断去除1的方式,来统计二进制中的1.
int CountOneBit(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
int main()
{
int n = CountOneBit(n);
return 0;
}
题目3:
5、编写代码将13的二进制序列的第5位修改为1,然后再修改回0.
00000000 00000000 00000000 00001101
|
00000000 00000000 00000000 00010000
00000000 00000000 00000000 00011101
可以看出要把二进制的哪一位置1,就是要给哪一位或1的问题,其余位不变,其实就值移动1的问题。
00000000 00000000 00000000 00011101
&
11111111 11111111 11111111 11101111
00000000 00000000 00000000 00001101
可以看出,要把哪一位置0,其实就是其余位&1,这一位&0的过程。这儿有一点小技巧,因为直接得到&的这个数不好弄,但它的反面好弄,在取反即可!
int main()
{
int a = 13;
//将a的第5位置1;
a = a | (a << 4);
printf("a = %d\n", a);
//将a的第5位置0;
//下面的处理注意一下
//直接不好弄,取反即可
a = a & (~(a << 4));
printf("a = %d\n", a);
return 0;
}
完结!!!