问题1:找出两数有多少比特位不同
编程实现:
两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?
输入例子:
1999 2299
输出例子:7
我们可以知道每个数都是32个bit位,所以我们每个位置都要比较
这很简单,我们先搞一个计数器,然我们可以让两数与个1即a&1,
b&1,如果a&1!=b&1,我们就让计数器+1,每对最后一位就行比较
之后,就让a和b都右移一位,这样循环32次,每次都比较最后一位是
否相同,最后就可以求出有多少bit位不同了。
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
int i = 0;
int count = 0;
printf("输入a的值:");
scanf_s("%d", &a);
printf("\n输入b的值:");
scanf_s("%d", &b);
for (i = 0; i < 32; i++)
{
if ((a & 1) != (b & 1))
{
count++;
}
a=a >> 1;
b=b >> 1;
}
printf("有%d个bit位不同\n", count);
system("pause");
return 0;
}
问题2:翻转二进制序列
编写函数:
unsigned int reverse_bit(unsigned int value);
这个函数的返回 值value的二进制位模式从左到右翻转后的值。
如:
在32位机器上25这个值包含下列各位:
00000000000000000000000000011001
翻转后:(2550136832)
10011000000000000000000000000000
程序结果返回:
2550136832
看到这个问题,其实我们有很多方法求出来它翻转后的值,
比如我们可以让第32bit位的值*2^31然后以此类推再让所有的
值都加起来,这不失为一种方法。(不建议)
关于二进制问题,其实很多题都是要灵活运用位运算,我
们可以一步一步来,不用急着写全局的代码,我们要将二进制
位逆置,我们首先得知道相对应二进制位上市什么吧,是1还是
0呢,并且我们得得到整个翻转后的二进制数,很明显这里得用
到循环但是怎么用?用到呢这就值得思考了。
想想我们可以将val从低位到高位都依次给到一个为全0的数
中去,然后每次给一位,就让val左移一位,一直到移动32次之后
处理前 val : 1010 1010 1010 0011
b : 0000 0000 0000 0000
首先找出val最后一位 为1
然后我们把1给到b中
再然后让val右移一位,b左移一位
处理后 val : 01010 1010 1010 001
b : 0000 0000 0000 0001
所以很多人代码会这样写:
unsigned int reverse_bit(unsigned int value)
{
unsigned int b = 0;
int i = 0;
for (i = 0; i < 32; i++)
{
if (value & 1)
{
b = b | 1;
}
value = value >> 1;
b = b << 1;
}
return b;
}
进行到这里你会发现其实这样是有问题的,因为我们要将b移动32次如果我们所以我们这样的话就会将所翻转的二进制数的最高位移没了,所以我们想想其实不是可以让b先左移然后再将val的低位放到b中吗?因为b为0,所以第一次移动相当于没移动这不就可以避免掉这个问题了。
#include<stdio.h>
unsigned int reverse_bit(unsigned int value)
{
unsigned int b = 0;
int i = 0;
for (i = 0; i < 32; i++)
{
b = b << 1;//第一次移动不影响b的大小
if (value & 1)
{
b = b | 1;
}
value = value >> 1;
}
return b;
}
int main()
{
unsigned int value = 0;
scanf_s("%d", &value);
printf("\n%u", reverse_bit(value));
system("pause");
return 0;
}
问题3:交换二进制的奇数位和偶数位
例如: 00001010
变成00000101
和前面翻转二进制数其实差不多,我们可以将二进制的从最高位到最低位依次求出,也就是sum,同样的ret如果左移32次的话,就会将最高位丢失,所以让ret=0,先无用的左移一次也就是把ret=ret<<1放到赋值前面,移位并求出最高位的值后,我们就让第31位给到ret的最低位,然后再左移,再让第32位给到最低位。总共执行16次就可以将所有的二进制奇数位和偶数位互换。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int exchange(int val)
{
int sum = 0;
int ret = 0;
int i = 0;
for (i = 16; i > 0; i--)
{
ret = ret << 1;
sum = (val >> (2 * i - 2) & 1);
ret = sum | ret;
ret = ret << 1;
sum = (val >> (2 * i - 1) & 1);
ret = ret | sum;
}
return ret;
}
int main()
{
int val = 14;
int num = EX(val);
printf("%d", num);
system("pause");
return 0;
}
问题4:找单独出现的数
一组数据中只有一个数字出现了一次。
其他所有数字都是成对出现的。请找出这个数字。(使用位运算)
例如:1 3 5 1 3 7 5
单独出现的数:7
又是二进制问题,首先要想到是否能用位运算解决,我们来分析题,
题上所有数字都是成对出现,只有一个数字是单独出现的,这我们要
知道一个公式a^b^a==b,这里我们就可以用到这个原理,arr[0]^arr
[1]^arr[2]……^arr[10]不就等于arr[0]^arr[10^arr[1]^arr[9]…^arr[8]
最后的值不就是那个单独出现的数字.
#include<stdio.h>
//位运算
int main()
{
int arr[11] = { 1, 2, 3, 4, 5, 5, 4, 3, 99, 2, 1 };
int alone = 0;
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
alone^=arr[i];
}
//原理:a^b^a==b
printf("%d", alone);
system("pause");
return 0;
}
问题5:写一个函数返回参数二进制中 1 的个数
写一个函数返回参数二进制中 1 的个数
比如: 15 0000 1111 4 个 1
程序原型:
int count_one_bits(unsigned int value)
{
// 返回 1的位数
}
这个比较简单
这里要知道n&(n-1)是什么意思,n=n&(n-1)就是每次都让n的二进制中少一个1。
#include<stdio.h>
int count_one_bits(unsigned int value)
{
int count=0;
while( value=value&(value-1))
{
count++;
}
return count;
}
int main()
{
unsigned int value=0;
scanf("%d",&value);
printf("%d",count_one_bits(value));
system("pause");
return 0;
}