异或操作的应用

1,异或运算的规则:

a) 0 xor 0 = 0

b) 0 xor 1 = 1

c) 1 xor 0 = 1

d) 1 xor 1 = 0


2, 异或运算的性质:

a)  a xor a = 0
b) (a xor b) xor c = a xor (b xor c)
c)  IF a xor b = c THEN a xor c = a xor (a xor b) = (a xor a) xor b = b


3, 异或的应用

Q1: 一个数组,除其中一个元素(如下面的99),其它的都是成对出现的,如何能快速找出那99的位置
……102,102,2,2,44,44,99,23,23,11,11 ……

请参考: 参考贴子

Answer 1:

把所有数组元素全部异或一下则得到非成对出现的元素99,然后顺序查找99的位置。时间复杂度为O(n)。

此解法较通用,适合如下两种特殊情况:

a),如……102,102,2,2,2, 2,44,44,99,23,23,11,11 ……(连续但存在相同元素)

b),如...... 102,2,44,23,11,99,11,23,44,2,102......(配对但不连续)


若数据无素不会出现3(a)和(b)中情况,那么可以采用一种更高效的算法:

Answer 2:

折半查找。

若数组a的元素个数为(n+1),则n+1必为奇数。数组a的序号为0到n。

left = 0; right = n; m = (left+right)/2;

int find99(left,right);

m = (n+0)/2,

IF: m为偶数,也即m两边的数量都为偶数,分别判断a[m]与a[m-1]、a[m+1]的值,若与a[m-1]相等,则99必在左侧,那么接下来就find99(left,m-1)。若与a[m+1]相等,则99必在右侧,那么find99(m+1,right)。若都不相等,则a[m] == 99,return m。
ELSE: 若m为奇数,也即m两边的数量都为奇数,分别判断a[m]与a[m-1]、a[m+1]的值,若与a[m-1]相等,则99必在右侧,find99(m+1,right)。若与a[m+1]相等,则99必在左侧,find99(left,m-1)。若都不相等,则a[m] == 99,return m。


Q2:一个很大的数组,里面有两个数只出现过一次,其他数都出现过两次,把这两个数找出来

ref :参考贴子

Answer 1:

        在题目给出的很大的数组中,除要找的两个不同的数字外,其它的数字都是成对出现的,根据上面说到的两个相同的数字的异或其结果为0。因此,如果将整个数组中的元素进行异或,所得到的结果应该是所求的那两个不成对的数字的异或结果。

        假定数组中两个不同的数字是95 ^ 99,则其异或的结果是0111100b,其中有4位是1,这表明这两个数字的二进制表示中有4位是不同的。(从右往左数) 它们分别是第3、4、5、6这4位,于是我们只需要

       将数组中所有元素中第6位为1的元素和0111100b异或,

or,将数组中所有元素中第5位为1的元素和0111100b异或,

or,将数组中所有元素中第4位为1的元素和0111100b异或,

or,将数组中所有元素中第3位为1的元素和0111100b异或。

就可以得到所求之两个数字中的一个数字。

        不妨以上面最后一条规则为例来进行说明:数组元素中第3位为1的数字,除所求的两个数字之外,都是成对出现的,它们所产生异或的结果肯定是0。而所求的那两个数字当中只有一个数字的第3位1。不妨假定这个数字是a(此时未知),另外一个要求的数字是b(此时未知)。很明显,将a (此时未知)和0111100b异或就可以得到b (此时已知),再用0111100b和已经求出来的b (此时已知) 进行异或就可以得到a (此时已知)。比如上面的95的第3位为1,所以用95 ^ 0111100b = 1011111b ^  0111100b = 1100011b = 99,再用99 ^ 0111100b = 1100011b ^ 0111100b = 1011111b = 95。

 


你可能感兴趣的:(c,算法)