[位操作]位操作有关的算法设计

在进行位操作算法设计之前,先了解位操作的一些细节知识点:

1. 位操作数据溢出的结果

2. 数据位提升的隐式转换

统计一个int类型整数对应的二进制数的1的个数:

int  NumberOf1Bits(int n)
{
	int cnt = 0;
	
	while(n != 0)
	{
		cnt++;
		n = n & (n - 1);
	}
	return cnt;
}

  分析一个这个程序,如果这个n是正数,没问题,最后肯定能到0,终止循环。但是对于一个负数,它能终止退出循环吗?答案是可以的。因为这个负数一个跟n-1做按位与操作,那么1的个数会一直减少,知道最后变成10000...0000这样的形式,也就是int能表示的最小的负数,n-1得到的结果就是0111...111变成了最大的正数,两个东西按位与得到的结果就是零,这个样子就结束了循环。

这个问题还有另外的一种解法,那就是移位:

int  NumberOf1Bits(int n) 
{
	int cnt = 0;
 
	for(int i = 0; i < 32; i++)
	{
		cnt += (n & 1);
		n = (n >> 1);
	}
	return cnt;
}

判断一个数是不是2的幂:

这个题目首先把负数排除在外,一个负数绝对不是2的幂。在来总结2的幂的数的特征:

1     2       4         8         16   ....

1    10    100    1000    10000   ....

特征就是在某一位中只有一个1,所以可以统计这个数字的1的个数,判断是不是2的幂。

bool isPowerOfTwo(int n) 
{
	int cnt = 0;
	while(n > 0)
	{
		cnt++;
		n = n & (n - 1);
	}
	return cnt == 1;
}

  当然利用移位的方式计算1的个数一样可行,这里还有一个简单的方法。看这些数字的特征是都只有一个1,那么它们和n-1按位与的结果一定是0。所以:

bool isPowerOfTwo(int n) 
{
	return (n > 0) && !(n & (n - 1));
}

  

逆序一个无符号整数数的各个bit位,得到一个新的无符号数:

uint32_t reverseBits(uint32_t n) 
{
	uint32_t res = 0;
	for(int i = 0; i < 32; i++)
	{
		if(n & 1 == 1)
		{
			res = (res << 1) + 1;
		}//if
		else
		{
			res = res << 1;
		}//else
		
		n = n >> 1;
	}//for
	
	return res;
}

  这个算法就是利用了按位与的相关知识点。

 逆序一个整型int:

算法的思想类似bit位的逆序,但是要考虑好负数与数据溢出的风险。

int reverse(int x) 
{
	int d = 0;
	int res = 0;
	
	while(x != 0)
	{
		if(abs(res) > INT_MAX / 10)
			return 0;
		d = x % 10;
		res = res * 10 + d;
		x = x / 10;
	}
	
	return res;
}

由于负数在求mod和除法的时候,符号是保留不变的,所以不用单独的考量负数的问题。但是在检验数据溢出的时候,不能等溢出了在去检测,要在还未溢出但是下次就要溢出时检测,返回0。

不用四则运算的加法

这里我们首先得到一个规律:对于数字的运算,除了四则运算,就是位运算了

题目描述:

给出两个整数a和b, 求他们的和, 但不能使用 + 等数学运算符。

不能用四则运算,那么就只剩下位运算了。

接下来借鉴计算机组成原理的加法运算器的工作原理来看。真正的加法运算可以分解为三个步骤:

1. 不考虑进位的加法运算,当然这种运算可以用按位异或运算代替。

2. 计算每一位的进位值,因为每一个进位都是往高位进一位,所以向左移动一位。

3. 把上面得到的两个结果相加,类似于一个递归的过程。

  所以代码实现:

int aplusb(int nums1, int nums2) 
{
	// write your code here, try to do it without arithmetic operators.
	int sum = 0;
	int carry = 0;
	
	do
	{
		sum = nums1 ^ nums2;
		carry = (nums1 & nums2) << 1;
		
		nums1 = sum;
		nums2 = carry;
	}while(nums2 != 0);
	
	return nums1;
}

  

原文地址:https://www.cnblogs.com/stemon/p/4594428.html