Java位运算的应用

2020-08-06  本文已影响0人  Heezier

一、判断整数的奇偶性

传统思路:

按照传统的思路,判断一个整数的奇偶性是通过用这个数与2求模,看运算结果是否为0

位运算思路:

Java语言中,所有数字存储在内存中,都要先转换成补码的形式。任何一个偶数用补码表示出来后,它的最后一个二进制位都是0,而奇数补码的最后一个二进制位都是1。所以,我们可以通过判断这个整数的补码的最后一位二进制数是0还是1,来判断这个数是偶数还是奇数。判断的方法就是用这个数与1进行按位与的操作,如果结果为0,那么这个数就是偶数,否则就是奇数。

  /**
     * 判断整数的奇偶, true表示偶数,false表示奇数
     */
    public static boolean  judgeParity(int x){
        return (x & 1) == 0;
    }

二、求绝对值

传统思路:

首先判断一个数a是否>=0,如果a>=0,则返回a本身,否则返回a的相反数

位运算思路:

任何一个整数与0进行异或运算后依然保持不变

任何一个整数与-1进行异或运算后再加上1,得到的结果就是这个数的相反数

数字-1用补码的形式表示出来,恰好是一个32位全为1的二进制串。这个二进制串与任何一个其他二进制串进行按位异或运算,都可以达到”取反”的效果,一个正数按位取反后再加1,得到的就是它相反数

int类型的正数经过带符号右移31位之后,得到的必然是0,而负数经过带符号右移31位得到的是-1。我们就可以通过右移所得到的这个0或者-1,判断出这个数是正数还是负数

  /**
     * 获取绝对值
     * int类型的正数经过带符号右移31位之后,得到的必然是0,而负数经过带符号右移31位得到的是-1。我们就可以通过右移所得到的这个0或者-1,判断出这个数是正数还是负数
     * 1.任何一个整数与0进行异或运算后依然保持不变
     * 2.任何一个整数与-1进行异或运算后再加上1,得到的结果就是这个数的相反数
     */
    public static int abs(int x){
       int i = x >> 31;//如果x为整数,则i为0,为负数i为-1
       return (x ^ i) - i;
    }

三、变量交换两个变量的值

传统思路:

借助中间变量来实现

位运算思路:

abb的运算结果等于a


    /**
     * 交换变量值
     * a^b^b的运算结果等于a
     *
     * @param a
     * @param b
     */
    public static void exchange(int a, int b){
       a = a ^ b;//g = x ^ y
       b = a ^ b;//h = g ^ y = x ^ y ^ y = x 还原了a的值,赋值给b
       a = a ^ b;//j = g ^ h = x ^ y ^ x
       System.out.println("交换结果:a=" + a + "  b=" + b);
    }

四、找出数组中只出现一次的元素

传统思路:方式有很多,我们随便写一种

//利用HashSetkey元素不重复的特性
        HashSet<Integer> set = new HashSet<Integer>();
        for (int i : array) {
            //如果存在,则删除
            if(!set.add(i)){
                set.remove(i);
            }

        }
        //最后剩下不重复的元素
        System.out.println("=======" +  set.toString());

位运算思路:

两个相同的数字进行异或运算,结果为0,而任何一个整数与0进行异或运算,其结果都是这个数本身。另外,任意N个整数进行异或操作,满足交换律

具体实现如下:

 /**
     * 位运算放方法 限定数组中只有一个只出现一次的元素
     * 思路:两个相同的数字进行异或运算,结果为0,而任何一个整数与0进行异或运算,其结果都是这个数本身。另外,任意N个整数进行异或操作,满足交换律。
     * @param array
     */
    public static void queryOnceBit(int[] array){
        int find = 0;
        for(int x: array){
            find = find ^ x;
        }
        System.out.println("只出现一次的元素" +  find);
    }

    /**
     * 有整型数组a和b,a数组中所有元素都出现在b数组中,但b数组比a数组多出一个元素
     * 思路:两个相同的数字进行异或运算,结果为0,而任何一个整数与0进行异或运算,其结果都是这个数本身。另外,任意N个整数进行异或操作,满足交换律。
     *
     */
    public static void queryOnceBit(int[] arrayA, int[] arrayB){
        // int[] arrayA = {1, 5, 6};
        // int[] arrayB = {5, 1, 8, 6};
        int find = 0;
        for(int i = 0; i < arrayA.length; i++){
            find = find ^ arrayA[i] ^ arrayB[i];
            //0^1^5^5^1^6^8 = 6^8
        }
        //6^8^6 = 8
        find = find  ^ arrayB[arrayB.length - 1];
        System.out.println("只出现一次的元素" +  find);
    }

五、字符串加密

假设有两个整数a和b ,a^b的结果为c。我们可以认为a就是原始数据,a与b进行异或运算所得到的c就是加密后的数据,b在加密过程中扮演着”密钥”的角色。

基础:无论是图片还是文本,在计算机当中都是以二进制数的形式进行存储的。既然是二进制数,那么每8位的二进制数,都可以转换成一个byte类型的数据。而N个8位二进制,就可以转换成一个byte数组。概括成一句话就是:任何形式的信息,在计算机当中都可以用byte数组来存储和表示。

 /**
     * 原理:a^b^b = a
     * @param text
     * @param key
     */
    public static void encoder(String text, byte key){
        byte[] bytes = text.getBytes();
        byte[] tranCodes = new byte[bytes.length];//用于保存每个加密后的字节
//        byte[] keyBytes = key.getBytes();//密钥
        System.out.println("原始字符串为:"+ text);
        //加密过程
        for (int i = 0;   i < bytes.length; i++) {
            tranCodes[i] = (byte)(bytes[i] ^ key);// 对每个字节进行加密
        }

        String encode = new String(tranCodes);//用加密后的字节数组创建字符串
        System.out.println("加密后的字符串:"+encode);//输出加密后的字符串
        //解密过程
        for (int i = 0;   i < bytes.length; i++) {
            bytes[i] = (byte)(tranCodes[i] ^ key);//对每个字节完成解密
        }

        String decode = new String(bytes);
        System.out.println("解密后的字符串:"+decode);//输出解密后的字符串
    }

六、计算一个二进制数当中1的个数

二进制数进行右移1位,然后再左移1位,如果经过两次位移运算,这个二进制数仍然保持不变,那么说明这个二进制数的最低位(也就是最右边那1位)上的数字为0,否则说明最低位为1。

00000101 右移一位 00000010

00000010 左移一位 00000100

操作之后不相等,则说明最后一位是1,相等则为0

无符号右移,左边填0,那么不断的无符号右移,当为00000000时则全部计算完毕

  /**
     * 计算输入int的二进制1的个数
     * @param x
     * @return
     */
    public static int count1(int x){
        int count=0;
        while(x!=0) {
            if((x>>1)<<1 != x) //对a进行"右移再左移",判断其结果是否等于原来的a
            {
                ++count;
            }
            x = x>>>1;//完成1次判断,对a进行无符号右移并把运算结果赋值给a自身
        }
        return count;
    }

其他应用遇到了再做更新。

参考:

Java位运算经典应用(一)

Java位运算经典应用(二)

Java位运算经典应用(三)

Java位运算经典应用(四)

上一篇 下一篇

猜你喜欢

热点阅读