位运算的原理和应用

1 十进制,八进制和十六进制

在这里插入图片描述

2 原码,反码和补码

在内存中,数据以二进制的方式存储,且最小单位是字节。对于有符号的数值,无论正反,计算机都是以补码的形式进行存储。
1)正数的原码,反码和补码都相同。
以整型数字4为例:
原码:00000000 00000000 00000000 00000100
反码:00000000 00000000 00000000 00000100
补码:00000000 00000000 00000000 00000100

2)负数的反码为原码除符号位外各位取反,补码是反码最后一位加1。
以整型数字-1为例:
原码:10000000 00000000 00000000 00000001
反码:11111111 11111111 11111111 11111110
补码:11111111 11111111 11111111 11111111

3 位运算符

在这里插入图片描述

/**
 * Created by JayLai on 23/11/2018
 */
public class BitwiseApp {

    public static void main(String[] args) {
        int a =  4;
        int b = -1;
        
        /**
         * 数据在内存中以二进制形式的补码存储,正数以0开头,负数以1开头
         * a: 00000000 00000000 00000000 00000100
         * b: 11111111 111111111 1111111 11111111
         */
        System.out.println(Integer.toBinaryString(a));
        System.out.println(Integer.toBinaryString(b));

        /**
         * int类型的取值范围: [-2^31 ~ 2^31 -1]
         * 计算原理:
         * 无符号情况下,算上值为0,32位二进制数一共有 2^32个
         * 正整数情况下,由等比数列计算出最大值为2 ^31 -1
         * 因此负数的最小值为-^31
         */
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MIN_VALUE);

        /**
         * 按位与运算
         * 两个操作数对应位数都是1结果位才是0,否则是0
         */
        System.out.println(a & b);

        /**
         * 按位或运算
         * 两个操作数对应位数都是0结果位才是0,否则是1
         */
        System.out.println(a | b);

        /**
         * 按位非运算
         * 将操作数二进制的所有位数全部取反
         */
        System.out.println(~a);
        System.out.println(~b);

        /**
        * 按位异或运算
         * 两个操作数对应位数相同为0,否则为1,符号位也要取反
        */
        System.out.println(a ^ b);

        /**
         * 左移运算符
         * 操作数的二进制数据向左移动指定位数,空缺部分补0
         * 左移n位后的值 等于原值乘以2的n次方
         */
        System.out.println(a << 2);
        System.out.println(b << 2);

        /**
         * 右移动运算符
         * 操作数的二进制数据向右移动指定位数,符号为是1,则右边空缺补充1,否在补0
         * 右移n位后的值 等于原值除以2的n次方的商
         */
        System.out.println(a >> 2);
        System.out.println(b >> 2);

        /**
         * 无符号右移
         * 不管正负标志位为0还是1,将该数的二进制码整体右移,左边部分总是以0填充,右边部分舍弃
         */
        System.out.println(a >>> 2);
        System.out.println(b >>> 2);

    }
}

4 位运算常见算法题目

4.1 统计二进制数中含有1的个数

请实现一个函数,输入一个整数,输出该树二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1.因此如果输入9,该函数输出2.

1)实现代码

/**
 * Created by JayLai on 11/12/2018
 */
public class NumberOf1App {

    /**
     * 字符串
     * 缺点:效率低
     * @param input
     */
    public static void method1(int input) {
        String str = Integer.toBinaryString(input) + "";
        int count = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == '1') {
                count++;
            }
        }

        System.out.println(count);
    }


    /**
     * 左移到运算
     * 缺点:需要循环32次
     * @param input
     */
    public static void method2(int input) {
        int count = 0;
        int flag = 1;

        for (int i = 0; i < 32; i++) {
            if ((input & flag) != 0)
                count++;

            flag = flag << 1;
        }

        System.out.println(count);
    }


    /**
     * 右移运算
     * 缺点:只适用于正整数,负数出现死循环
     * @param input
     */
    public static void method3(int input) {
        int count = 0;
        while (input != 0) {
            if ((input & 1) == 1)
                count++;
            input = input >> 1;
        }

        System.out.println(count);
    }

    /**
     * 无符号右移运算
     * @param input
     */
    public static void method4(int input) {
        int count = 0;
        while (input != 0) {
            if ((input & 1) == 1)
                count++;
            input = input >>> 1;
        }

        System.out.println(count);
    }

    /**
     * 移位运算
     * 思路:使最右边一个1变为0,不断重复直到所有1变为0
     * @param input
     */
    public static void method5(int input) {
        int count = 0;
        while (input != 0) {
            input = input & (input - 1);
            count++;
        }

        System.out.println(count);
    }
    
    public static void main(String[] args) {
        int[] numArray = {0, 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF};
        for (int num: numArray
             ) {
            method1(num);
            method2(num);
//            method3(num);
            method4(num);
            method5(num);
        }
    }
}

2)测试结果

在这里插入图片描述

4.2判断一个正整数是不是2的整数次方

1)代码实现

/**
 * Created by JayLai on 16/11/2018
 */
public class PowerOf2App {

    public static void method1(int input){

        int flag = 1;
        while (input >= flag){
            if(input == flag){
                System.out.println(input + "是2的整数次方");
                return;
            }
            flag = flag << 1;
        }

        System.out.println(input + "不是2的整数次方");
    }

    public static void method2(int input){
        int ret = input & (input - 1);

        if( ret == 0){
            System.out.println(input + "是2的整数次方");
        }else {
            System.out.println(input + "不是2的整数次方");
        }
    }



    public static void main(String[] args) {
        int flag = 1;
        for(int i = 1; i < 10; i++){
            method1(flag);
            method2(flag);
            flag *= 2;
        }

    }
}

2)测试结果
在这里插入图片描述

4.3 输入两个整数m和n,计算需要改变m的二进制表示中的多少为才能得到n

1)实现代码

/**
 * Created by JayLai on 16/11/2018
 */
public class NUmOfChangeApp {

    /**
     * 先异或,再求二进制数中1的个数
     * @param m
     * @param n
     */
    public static void method1(int m, int n) {
        int input= m ^ n;

        int count = 0;
        while (input != 0) {
            input = input & (input - 1);
            count++;
        }

        System.out.println("需要改变" + m + "的二进制表示中的"+ count +"位才能得到" + n);
    }

    public static void main(String[] args) {
        method1(10, 13);
    }
}

2)测试结果
在这里插入图片描述

4.4 交换2个变量a和b,不能创建临时变量

1)实现代码

  /**
     * Created by JayLai on 16/11/2018
     */
    public class VariableSwapsApp {
    
        /**
         * 四则运算
         * @param a
         * @param b
         */
        public static void method1(int a, int b) {
            a = a + b;
            b = a -b ;
            a = a - b;
            System.out.println("交换后的数字a = " + a + " b = " + b);
        }
    
        /**
         * 异或运算
         * @param a
         * @param b
         */
        public static void method2(int a, int b) {
            a = a ^ b;
            b = a ^ b;
            a = a ^ b;
            System.out.println("交换后的数字a = " + a + " b = " + b);
        }
        
        public static void main(String[] args) {
            int a = 6;
            int b = 7;
            System.out.println("交换前的数字a = " + a + " b = " + b);
            method1(a, b);
            method2(a, b);
        }
    }

2)测试结果
在这里插入图片描述

5 参考文献

[1] Robert, Lafore., Java数据结构和算法. 第2版,中国电力出版社.
[2] 何海涛, 剑指off,第1版,电子工业出版社出版

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值