编程中 常见的位运算问题
2016-08-26 16:39
218 查看
常见的位运算问题
二进制数和字符串一样都是编程问题中常遇见的一系列问题 ,许多人觉得很难 ,为什么呢?因为 ,里面计算可能会用的一些想不到的公式 和 计算思路 。
所以 ,许多的人觉得二进制问题很难实现 。
另外 ,在编程中的许多问题如果使用位运算的方法解决的话,可能会更简单。当然也可能没什么效果哦。
编程中的位运算要用到位操作符
位操作符包括
& 与
| 或
^ 异或
接下就由我向大家介绍一些这样的题目(可以使用位运算计算的):
1、两数交换(不允许创建临时变量)
两个数的交换问题,相信的大家都不是很陌生吧 !!这是一个很简单的问题 ,但是就是有一些变态就是爱给人出难题 ————说不能创建临时变量
看到后是不是很无奈啊;
下面我来讲几种方法吧!!
方法一:
a = a+b;//////a现在等于a 与 b的和b = a -b;//////b现在等于 (a 与 b的和) -b 为 a最初的值
a = a -b;//////a现在等于 (a 与 b的和) -b 为 b最初的值(因为b的当前值为a的最初值)
void Swap(int *a,int *b) { *a = *a+*b; *b = *a -*b; *a = *a -*b; }但是这个方法有个缺陷 ,就是两数相加 ,有可能会超出整型值的范围。
方法二:
既然加减法可行 ,当然也可以了a = a*b;//////a现在等于a 与 b的积
b = a /b;//////b现在等于 (a 与 b的积) /b 为 a最初的值
a = a /b;//////a现在等于 (a 与 b的积) /b 为 b最初的值(因为b的当前值为a的最初值)
<span style="font-size:18px;">void Swap(int *a,int *b) { *a = *a**b; *b = *a /(*b); *a = *a /(*b); }</span>但是,这个方法也是有缺陷的,就是 除数不能为零
方法三:
就是使用异或的方法a = a^b;//////a现在等于a 与 b异或的结果
b = a^b;//////b现在等于 (a 与 b异或的结果) ^b 为 a最初的值
a = a^b;//////a现在等于 (a 与 b异或的结果) ^b 为 b最初的值(因为b的当前值为a的最初值)
<span style="font-size:18px;">void Swap(int *a,int *b) { *a = *a^*b; *b = *a ^*b; *a = *a ^*b; }</span>
这就是将平常的问题使用二进制的方法解决。。
2、计算一个整数二进制形式中1的个数
写一个函数返回参数二进制中 1 的个数比如: 15 0000 1111 4 个 1
这个问题如果用平常的方法一个一个的算的话,写出来的代码会很繁琐 ,同样错误也不少
下面就让哥来介绍一种简单方法吧
要想解决这个问题就要 知道一个公式
n = n&(n -1);
这个公式只要运行一次 n的二进制式中就少一个 1
例如 :
n = 15
1111
n = 15&14
1111 & 1110 = 14
n = 14&13
1110 & 1101 = 12
n = 12&11
1100 & 1011 = 8
n = 8 & 7
1000&0111 = 0
运行了四次 所以 15的二进制数中有4个1
int count_one_bits(int value) { int ret = 0; while(value) { value = value &(value-1); ret++; } return ret; }
3、计算一个整数二进制形式中0的个数
既然有求二进制数中1的个数 ,就肯定有求 0的个数的写一个函数返回参数二进制中 0的个数
比如: 15 0000
0000 0000 0000 0000 0000 0000 1111 28 个 1
当然,你可以先求出1的个数 ,然后一减就是 0的个数
下面就让哥再来介绍一种简单方法吧
n = n|(n + 1);
例子就不用举了 ;和求一的个数差不多
int count_zero_bits(int value) { int ret = 0; while(value+1) { value = value |(value+1); ret++; } return ret; }
4、将二进制位模式从左到右翻转后的值
编写函数:unsigned int reverse_bit(unsigned int value);
这个函数的返回 值value的二进制位模式从左到右翻转后的值。
例如
在32位机器上25这个值包含下列各位:
00000000000000000000000000011001
翻转后:(2550136832)
10011000000000000000000000000000
程序结果返回:
2550136832
代码实现:
unsigned int reverse_bit(unsigned int value) { unsigned int ret = 0 ; int i = 0; int num = 0; for(i = 0;i<32;i++) { num = (value>>i)&1;//求出每一位二进制位的数 ret += num* pow(2,31-i);//根据要求重新计算 } return ret; }
5、找出数组中只出现一次的两个数
原题目是这样的:一组数据中只有两个数字出现了一次。
其他所有数字都是成对出现的。请找出这个数字。(使用位运算)
题目中明确表示要使用位运算来解决这个问题;
在这里就要知道位操作符(^ 异或)的特点是什么?
异或操作符 :
1、两个相同的数异或后为 0 ;
2、任何一个数与0异或的结果都是这个数。
在这个题目中就要运用到这个特点 ,
要解决这个问题 :就要将数组中的数全部异或 得到的结果 就是只出现一次的两个数异或后的结果 ,
然后,根据这个结果将数组分为两部分,将这两部分的数各自异或后得到的结果就是要找的这两个数...
代码实现
void search_date(int arr[],int len ,int *num1,int *num2)//num1 与 num2为要找的那两个数的地址 { int num = 0; int i = 0 ; int m = 0 ; for(i = 0;i<len;i++) { num ^=arr[i]; }//求出所有数异或的结果num while(((num>>m)&1)!=1)//找到num二进制式中为1的位 { m++; } for(i = 0 ;i<len;i++) { if(((arr[i]>>m)&1) ==1)//将数组分为两组 *num1 ^=arr[i];//各自异或 else *num2 ^=arr[i]; } }
相关文章推荐
- 使用位运算实现网页中的过滤、筛选功能实例
- mysql binlog二进制日志详解
- C语言二进制思想以及数据的存储
- C语言 位运算详解及示例代码
- 详解C++编程中对二进制文件的读写操作
- 整理C# 二进制,十进制,十六进制 互转
- C#枚举中的位运算权限分配浅谈
- 在ASP.NET 2.0中操作数据之五十四:添加新记录时包含一个文件上传选项
- c#二进制逆序方法详解
- JS幻想 读取二进制文件第1/2页
- 使用jscript实现二进制读写脚本代码
- JavaScript读二进制文件并用ajax传输二进制流的方法
- C#中图片、二进制与字符串的相互转换方法
- C#二进制序列化实例分析
- JavaScript前端开发之实现二进制读写操作
- shell 基本计算、逻辑运算、位运算详解
- PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明
- javascript 二进制运算技巧解析
- 如何判断一个整数的二进制中有多少个1
- MSSQL 将截断字符串或二进制数据问题的解决方法