前言
路漫漫其修远兮,吾将上下而求索;
例一、
思路:首先是需要得到这个十进制数据的每一位,对得到的每一位上的数值判断奇偶,然后转换成对应的0或者1;倘若这个数的每一位均是偶数,那么每一位都会变成0,即整体为0;在高位的0可以省略:
代码如下:
//小乐乐改动数字
int main()
{
//输入
int input = 0;
scanf("%d", &input);
int sum = 0;//整合为一个数
int count = 0;//记录数的位
int ret = 0;//记录每一位的数字
while (input)
{
ret = input % 10;//得到每一位
if (ret % 2 == 0)//偶数
ret = 2;
else//奇数
ret = 1;
sum += ret * pow(10, count);
//调整
input /= 10;
}
printf("%d\n", sum);
return 0;
}
为什么循环结束的标志是 input == 0?
- 当input 只有一位的时候,也是需要对其”位“上的数字进行奇偶判断的,在循环之中input %10 可以得到这一位的数字,而 intput /= 10 每执行一次去掉一位的数;即 intput /= 10 是在调整位数;想要得到对应位上的数字,有多少位,便要使用相应次数的 input %10 与 intput /= 10;而当input /10 为 0时,代表input 为个位数,仅需执行一次循环中的代码便可;故而while 的判断条件为input == 0;
例二、
题目:输入一个整数(int 类型的数据) ,并计算统计其二进制数中1 的个数
思路一:联想到得到十进制数的每一位:通过 %10 与 /10 ;同理,对于二进制数来说,%2 与 /2 也可以得到对应的二进制位,然后再与1作比较即可;
代码如下:
//思路一
int NumberOfBinary1_1(unsigned int input)
{
int count = 0;
while (input)
{
if (input % 2 == 1)
count++;
//调整
input /= 2;
}
return count;
}
int main()
{
unsigned int input = 0;
scanf("%d", &input);
int count = NumberOfBinary1_1(input);
return 0;
}
思路二:
从低位开始找:
利用 右移操作符 >> 得到二进制位中的每一位,然后与1按位与&,利用& 的特性,二进制位上有0变为0,全一才为1;
代码如下:
//思路二
int NumberOfBinary1_2(unsigned int input)
{
//得到每一个二进制位
int count = 0;
int i = 0;
for (i = 0; i < 32; i++)//循环32次
{
if ((input >> i) & 1 == 1)
count++;
}
return count;
}
int main()
{
unsigned int input = 0;
scanf("%d", &input);
int count = NumberOfBinary1_2(input);
return 0;
}
思路三:
从高位开始找:
二进制中的每一位数据代表着2的多少次方,倘若1000 与 0111 按位与的话,其结果变为0;一个2^0 到2^(n-1) 之间的数求和,即等差数列求和,其第一项为1,倍数为2,其和为2^n-1 ; 显然,1000对应的十进制数字为8,0111对应的十进制数字为 7 ;
按位与& 的特点是:有0为0,全1才为1;当一个二进制序列与(二进制序列 - 1)按位与 之后势必会丢失一个高位;而低位中的1在进行按位与& 的时候并不会对原数二进制位上除最高位以外的位的数据造成影响;那么除掉了多少个二进制位便代表着有该二进制序列中有多少个1;
代码如下:
//思路三
int NumberOfBinary1_3(unsigned int input)
{
int count = 0;
while (input)
{
input = (input - 1) & input;
count++;
}
return count;
}
int main()
{
unsigned int input = 0;
scanf("%d", &input);
int count = NumberOfBinary1_3(input);
return 0;
}
例三、
题目:打印整数(int 类型的数据) 二进制的奇数位和偶数位
注:此处认为二进制位的最低位为0位;
思路:得到二进制位的奇数位与偶数位,不难想到使用for 循环i 逐渐递增,配合右移操作符 >> ,然后再分别打印
代码如下:
//打印整数二进制的奇数位和偶数位
void PrintBinary(int n)
{
int i = 0;
printf("二进制的奇数位:");
for (i = 30; i>=0; i -= 2)//奇数位
{
printf("%d ", (n >> i)&1);//有0为0,全1才为1
}
printf("\n二进制的偶数位:");
for (i = 31; i>0; i -= 2)
{
printf("%d ", (n >> i) & 1);
}
}
int main()
{
PrintBinary(118);
return 0;
}
例四、
题目:求两个数(int 类型的数据) m、n的二进制位表达式之中,有多少比特位不同;
思路一:
创建一个计数器count , 然后再分别取得m、n 的二进制位进行比较,不相同便count++;
代码如下:
//思路一
int calc_diff_bit_1(int m , int n)
{
//计数器
int count = 0;
//分别比较m n中的二进制位
for (int i = 0; i < 32; i++)
{
if (((m >> i) & 1) != ((n >> i) & 1))
count++;
}
return count;
}
int main()
{
int ret = calc_diff_bit_1(118, 40);
printf("%d\n", ret);
return 0;
}
思路二:
回顾之前学习的操作符,按位异或^ 的功能: 相同为0,相异为1;
于是乎便可以先让m 与n 按位异或,然后求所得结果中的 1 的个数,便是不同比特位的个数;(求一个二进制序列之中1的个数,例二中列举出了三种方法);
代码如下:
//思路二
int calc_diff_bit_2(int m, int n)
{
int ret = m ^ n;//相同位0,相异位1
//此处采用例二中的第三种方法来计算二进制序列中1的个数
int count = 0;
while (ret)
{
ret = ret & (ret - 1);
count++;
}
return count;
}
int main()
{
int ret = calc_diff_bit_1(118, 40);
printf("%d\n", ret);
return 0;
}
例五、
题目:交换奇偶位;写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换;
注:此处认为二进制位的最低位为0位;
思路:你可能会联想到之前练习的”旋转字符串“类型的题目,可以先得到最右边的二进制位,然后再将剩余的二进制位依次向右移动,但是针对”比特位“进行操作显然是不方便的;
当所要交换的数据有偶数个的时候,便可以将偶数位上的所有的数据统一向左移动到奇数位上,对于奇数位上的数来说同理,将奇数位上的所有的数据统一向右移动到奇数位上;这样便可以达到奇偶项上的数的交换;
如何对比特位进行操作?显然是必须使用位操作符或者移位操作符,复习如下:
我们可以将奇数位上全是1的数与目标数值进行按位与,得到目标数值中奇数位上数据,再利用右移操作符>> 将奇数位上的数据向右移动一位;同理,可以将偶数位上全是1的数与目标数值进行按位与,得到目标数值中偶数位上的数据,然后再利用左移操作符<< 将偶数位上的数据向右移动一位;最后再将二者相加即可;
代码如下:
#define SWAP_BIT(n) (((n&0xaaaaaaaa)>>1)+((n&0x55555555)<<1))
int main()
{
int n = 0;
scanf("%d", &n);
printf("%d\n", SWAP_BIT(n));
return 0;
}
总结
1、对于二进制位的操作,需要用到位操作符与移位操作符,对这些操作符要熟悉
2、求一个数值二进制位中1 的个数,计算 原数& (原数-1) 的次数 便可,这是一个很好的方法,因为无需遍历;
3、经过以上例题,可以感受到,常会用到右移操作符>>、按位与&、按位异或^