编程中 常见的位运算问题

本文介绍了五种使用位运算解决问题的方法,包括不使用临时变量进行两数交换、计算二进制中1和0的数量、二进制位翻转及找出数组中唯一出现一次的两个数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

常见的位运算问题

二进制数和字符串一样都是编程问题中常遇见的一系列问题 ,许多人觉得很难 ,为什么呢?

因为 ,里面计算可能会用的一些想不到的公式  和 计算思路 。
所以 ,许多的人觉得二进制问题很难实现 。
另外 ,在编程中的许多问题如果使用位运算的方法解决的话,可能会更简单。当然也可能没什么效果哦。


编程中的位运算要用到位操作符  
位操作符包括 


& 与
|  或
^ 异或

接下就由我向大家介绍一些这样的题目(可以使用位运算计算的):


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];
	}
}

























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值