前言
位运算是在算法设计中的一种非常重要和高效的方法,常见的有与运算,非运算,异或运算。我们常用的比较多的可能就是异或运算,又叫无进位相加。
1.1 取非运算----(~)
取非运算其实就是和我们的无符号数取反码类似,就是将数对应的二进制所有位取反,0变为1,1变为0;
如15的二进制形式为1111 ,则15的非~15就是为0000
如17的二进制形式10001 , 则17的非~17就是01110
 
1.2与运算-----(&)
与运算就是只有当两个数同时为1时最后结果才会为1,否则只要有一放为0,则最终结果就为0;
如15的二进制形式为1111 ,如17的二进制形式10001 
则15&17=1111&10001=00001,最终结果为1
 
1.3异或运算-----(^)
这里异或符号就是我们机组中的圈里面一个+,异或叫无进位相加。指的是0异或任何数都为任何数,任何数异或本身都为0。异或运算满足结合律。
0^0=0,   1^1=0,     0^1=1
 
2. 位运算相关运用
2.1. 交换两个数据
我们可以利用异或运算的特性来交换两个数的位置,而不需要开辟多余空间,更重要的是位运算的速率是非常快的。
a=a^b  //改行执行后 a=a^b  b=b
b=a^b //改行执行后 a=a^b  b=a^b^b=a
a=a^b //改行执行后 a=a^b^a=b  b=a
    public  static void fun(int a ,int b){
        System.out.println("交换前"+a+",,,,,"+b);
        a=a^b;
        b=a^b;
        a=a^b;
        System.out.println("交换后"+a+",,,,,"+b);
    }
 
则最后成功交换过来了。
 
 
注
用为交换两个数时,两个数的值是可以相同的,但是两个数不能指向同一个内存,你要指向同一个内存就相当于对同一个数进行异或运算,最后结果就会被消为0.
 
2.2 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数
当一组数只有一个数出现了,奇数次则寻找起来还是比较简单的,直接将所有数异或就可以了。
 比如为a,b,b,b,b,c,c,d,d.
 相同数异或为0.则偶数个相同的数异或在一起就是为0.则最后就只会保留那个出现奇数次的数。
    public static  int findodd(int a[]){
        int count=0;
        for (int x:a){
            count^=x;
        }
        return count;
    }
 

 
 
2.3 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数
当出现了两个奇数次数,方法相同只是多加了一步。首先还是先将所有的数都异或到一起。结果为哪两个奇数次的异或。
 如a,b,c,c,d,d,e,e,f,f.
 这全部异或到一起的结果为a^b用eor表示。
 因为a和b为两个不同的数,这eor一定不会为0.既然不为0,这eor所表示的二进制必定存在一位为1,假设第三位为1.eor=xxxxxx100.这是eor所表示的二进制位,第三位不为0.然后我们就可以帮所有的数分为两类,一类为第三位为1,一类为第三位为0.因为第三位不是1就一定是0.
 **且两个奇数次数一定分布在两个不同的区域里。
 
然后将第三位为0的这一区域所有数异或起来。用eor1表示为a或b
 则最终eor=a^b, eor1=a或b.
 则若eor1=a 则eor^eor1=b
 则若eor1=b 则eor^eor1=a.
 则最终两个数为eor1和eor1^eor.
2.3.1 如何找到第一位不为0,也就是说你怎么找到a^b的第三位。
这里就需要用到一个公式,找到右侧第一位不为0的数。
int right=eor&(~eor+1);  //取出最右侧不为0的数
如eor=1000100,
~eor=0111011+1=0111100&1000100=0000100
 
代码为
//    一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数
    public  static  void findTwoOdd(int a[]){
        int eor=0;
        int eor1=0;
        for(int i:a){
            eor=eor^i;
        }
        int right=eor&(~eor+1);  //取出最右侧不为0的数
        for (int j:a){
            if((j & right)==0){
                eor1=eor1^j;
            }
        }
        System.out.println(eor1+","+(eor^eor1));
    }
 

 
 
3,思考
若题目中不告诉你有多少个数出现了奇数次,让你找出所有出现奇数次的数,能否用位运算找出?若可以找出则应该怎么找出?



















