Algorithm:位运算的这些小技巧你知道吗?

 

位运算的巧妙之处

算法中,位运算可以巧妙运用在一下几个方面:

1、判断奇偶数 => x&1

2、判断数x中第k ( 从右至左 ) 位是1还是0

​ 法1:( x >> ( k - 1 ) ) & 1

​ 法2:x & ( 1 << ( k - 1 ) )

3、交换两个整数变量 a , b 的值

a = a ^ b;
b = b ^ a;
a = a ^ b;

这里为什么能这样做,在后面的异或运算中会说明;

4、不用判断语句,求整数绝对值

return (value ^ (value >> 31))-(value >>31)

同样在异或运算中说明;

应用

二进制中1的个数

描述:实现一个函数,输入一个正整数,输出该数二进制表示中1的个数。

例:9的二进制表示为1001,有2位是1;

思路:循环运用判断x的第k位是否为1的方法;

int count=0;
while(value)
{	
	count += value & 1;
	value = value >> 1;
}
return count;

方法二:

&运算有这样一个性质:a = ( a - 1 ) & a ; 这样a就能消除最低位的一个1

思路:利用这一性质,我们可以每次将value-1,然后与自己&,能做多少次这样的操作就说明有多少个1;

int count=0;
while(value)
{
	value = (value - 1) & value;
	count++;
}
return count;

异或运算的巧妙之处

性质

异或又称不进位加法,两个数相异或,对应位相同则为0,不同则为1;

具有以下性质:

1、a ^ a = 0;

2、0 ^ a = a;

3、异或具有交换律和结合律

​ b ^ c = c ^ b;

​ a ^ b ^ c = a ^ ( b ^ c) = ( a ^ b ) ^ c;

4、( -1 ) ^ a =!a;

应用

交换两个变量的值

交换变量a,b的值

a = a ^ b;
b = b ^ a;
a = a ^ b;

利用异或运算的交换律和结合律,可以得到如下:

1、a = a ^ b;

2、b = b ^ a;

把1式代入2式中,此时 b = b ^ ( a ^ b ) ,则 b = b ^ b ^ a = a;

3、a = a ^ b;

将1式和 b = a 代入3式,则 a = a ^ b ^ a = b;

不用判断语句,求整数绝对值

return (value ^ (value >> 31))-(value >>31)

1、若value为正数,则value二进制表示中最高位一定为0,那么 value >> 31 =0;

value ^ (value >> 31) = value ^ 0 = value;

value - (value >> 31) = value - 0 = value;

即正数的绝对值仍是自身;

2、若value为负数,则value二进制表示中最高位一定为1,那么 value >> 31 = 111…1 ,一共32个1,即-1;

value ^ (value >> 31) = ! value;

而负数以补码形式存放,补码等于绝对值的原码取反+1;

那么这里 ! value - (value >> 31) => ! value +1 即得到的是value的绝对值;

如果理解有困难,可以看这个例子:

如何找唯一成对的数?

问题描述:1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,在不用辅助存储空间的前提下,设计一个算法,将它找出来;

思路:根据异或性质1: a ^ a = 0;可以用来去重;

令T = 1 ^ 2 ^ 3 ^… ^ 1000 ;

那么遍历数组的同时将当前数字与 T 异或,在数组中只出现一次的数字会与 T 中的该数字相抵消,从而去重;最终会剩下重复的那个元素,因为它在数组和T中一共出现3次;

举一个只有11个数的例子: 重复的元素在任意位置出现都是可以找出来的;

int T=0;
for(int i=1;i<=1000;i++)
{
	T=T^i;      
}
for(int i=0;i<=1000;i++)
{
	T=T^A[i];
}
return T;

如有错误,感谢指正!

posted @ 2020-05-21 09:38  Luweir  阅读(120)  评论(0编辑  收藏  举报