【C】交换一个数字的奇数位与偶数位

  这里实现了交换一个数字的奇数位与偶数位,其交换规律是二进制序列中的第0位与第1位交换,第2位与第3位交换,第4位与第5位交换,……

1、算法思想

a.得到该数字的奇数位;

b.得到该数字的偶数位;

c.所有的奇数位右移一位变成偶数位;

d.所有的偶数位左移一位变成奇数位;

e.新的偶数位 按位或 新的奇数位 即可得到交换奇偶顺序后的数字。

  不妨假设最右边的位为第0位,也就是一个偶数位。那么如何得到一个数字的奇数位呢?

int num = 7; //        0 1 1 1
             //  奇数位 0   1    只想要得到0 1,就要保证偶数位上的数字为0(清0),
             //                 奇数位上的数字不发生变化(保留原值),这里考虑按位与,
             //                 1.奇数位上的数字按位与1则不会发生变化,
             //                 2.偶数位上的数字按位与0实现清0,
             //                 于是可以写出这个按位与的数字 0XAAAAAAAA,
             //                 其二进制序列为:1010 1010 1010 1010 1010 1010 1010 1010
             //                                 A    A    A    A    A    A    A    A
             //
             //                               1010 1010 1010 1010 1010 1010 1010 1010
             //                             & 0000 0000 0000 0000 0000 0000 0000 0111
             //                               0000 0000 0000 0000 0000 0000 0000 0010    

  如何得到一个数字的偶数位呢?

             //        0 1 1 1
             //  偶数位   1   1  只想要得到1 1,就要保证奇数位上的数字为0(清0),
             //                 偶数位上的数字不发生变化(保留原值),这里考虑按位与,
             //                 1.偶数位上的数字按位与1则不会发生变化,
             //                 2.奇数位上的数字按位与0实现清0,
             //                 于是可以写出这个按位与的数字 0X55555555,
             //                 其二进制序列为:0101 0101 0101 0101 0101 0101 0101 0101
             //                                 5    5    5    5    5    5    5    5
             //
             //                               0101 0101 0101 0101 0101 0101 0101 0101
             //                             & 0000 0000 0000 0000 0000 0000 0000 0111
             //                               0000 0000 0000 0000 0000 0000 0000 0101 

  所有的奇数位右移一位变成偶数位:

             //                       奇数位  0000 0000 0000 0000 0000 0000 0000 0010
             //                       >> 1   0000 0000 0000 0000 0000 0000 0000 0001

  所有的偶数位左移一位变成奇数位:

扫描二维码关注公众号,回复: 122160 查看本文章
             //                       偶数位  0000 0000 0000 0000 0000 0000 0000 0101  
             //                       << 1   0000 0000 0000 0000 0000 0000 0000 1010 

  新的偶数位 按位或 新的奇数位:

             //                新的偶数位      0000 0000 0000 0000 0000 0000 0000 0001 
             //              新的奇数位 |或    0000 0000 0000 0000 0000 0000 0000 1010 
             //                交换后的数字    0000 0000 0000 0000 0000 0000 0000 1011 
             //                                                  11

  从本质上来说,按位或运算可以理解为 相同位(同为0或者同为1)的和的一半 加上 不同位(一个为1,一个为0)的和。接下来通过下面的示例来剖析下按位或运算:

int num1 = 7; //       0 1 1 1
int num2 = 3; //   +   0 0 1 1
              //       1 0 1 0
 
             //相同位   0   1 1
             //相同位+  0   1 1
             //        0 1 1 0 
             //        0 4 2 0
             //相同位的一半也就是(4+2)/2=3

             //相同位   0   1 1
             //相同位&  0   1 1
             //        0 0 1 1 
             //        0 0 2 1    2+1=3

             //相同位   0   1 1
             //相同位|  0   1 1
             //        0 0 1 1 
             //        0 0 2 1    2+1=3

	         //不同位     1
             //   +      0
             //          1        2*2=4

	         //不同位     1
             //   |      0
             //          1        2*2=4

  加法运算可以这样理解:

//num1+num2的运算可以理解为 相同位的和(6) 加上 不同位的和(4),得到的结果也是10,
//其本质是 相同位的按位与的和(ps:由于不同位(1或者0)时按位与是0,所以这里用相同位的按位与) 
//加上 所有位的按位或的和。

  按位或运算可以这样理解:

int num1 = 7; //       0 1 1 1
int num2 = 3; //   |   0 0 1 1
              //       0 1 1 1    按位或得到的值为7

             //相同位   0   1 1
             //相同位&  0   1 1
             //        0 0 1 1 
             //        0 0 2 1    相同位与得到2+1=3
             //不同位     1
             //不同位&    0
             //        0 0 0 0    不同位与得到0

             //相同位   0   1 1
             //相同位|  0   1 1
             //        0 0 1 1 
             //        0 0 2 1    相同位或得到2+1=3
	         //不同位     1
             //   |      0
             //          1        不同位或得到2*2=4

//num1 | num2的运算就相当于是 相同位的和的一半 加上 不同位的和。

  这里定义一个宏来实现交换奇数位与偶数位的算法:

# define SWAP_ODD_EVEN(NUM) ((((NUM) & (0X55555555)) << 1) | (((NUM) & (0XAAAAAAAA)) >> 1))

2、源代码

a.输出二进制序列

    对num模2除2即可。

/*
*	函数名称:OutputBinary
*
*	函数功能:输出一个数字的二进制位
*           从右往左读,表示从高位到低位,
*	        不足32位的,右边补0。
*
*	入口参数:num
*
*	出口参数:void
*
*	返回类型:void
*/

void OutputBinary(unsigned int num)
{
	unsigned int one_bit_num = num;

	if (0 == num)
	{
		printf("%d", one_bit_num);	
	}

	while (num)
	{
		one_bit_num = num % 2;
		printf("%d ", one_bit_num);
		num >>= 1;
	}

	printf("\n");

	return;
}

   不足:首先,每次需要补齐二进制序列至32位,其次,数字必须为无符号整型,并且需要对0进行判断,最后从右往左看每一位的数字,很不人性化。

   改进:遍历变量one_bit_num从31到0,然后移位one_bit_num再与1

/*
*	函数名称:OutputBinary
*
*	函数功能:输出一个数字的二进制位
*
*	入口参数:num
*
*	出口参数:void
*
*	返回类型:void
*/

void OutputBinary(int num)
{
	int one_bit_num = 0;

	for (one_bit_num=31; one_bit_num>=0; one_bit_num--)
	{
		printf("%d ", ((num >> one_bit_num) & 1));
	}

	printf("\n");

	return;
}

b.主函数

#define _CRT_SECURE_NO_WARNINGS 1

/*
* Copyright (c) 2018, code farmer from sust
* All rights reserved.
*
* 文件名称:SwapOddEven.c
* 功能:写一个宏可以将一个数字的奇数位和偶数位交换。
*
* 当前版本:V1.0
* 作者:sustzc
* 完成日期:2018年4月11日21:48:09
*/

# include <stdio.h>
# include <assert.h>

# define SWAP_ODD_EVEN(NUM) ((((NUM) & (0X55555555)) << 1) | (((NUM) & (0XAAAAAAAA)) >> 1))

int main(void)
{
	unsigned int num = 0;
	unsigned int ret = 0;

	printf("input one num:");
	assert(1 == scanf("%d", &num));

	printf("swap before:");
	OutputBinary(num);

	ret = SWAP_ODD_EVEN(num);

	printf("swap after: ");
	OutputBinary(ret);
	printf("now,num is %d\n", ret);

	return 0;
}

3、输出结果

 

 

 

 

猜你喜欢

转载自blog.csdn.net/sustzc/article/details/79912156
今日推荐