【位运算】你学废了么?

目录

位运算

运算符

位运算性质 

位运算理解(实现加减乘除)

位运算操作


燃烧吧!!!大脑!!!

位运算

运算符

逻辑运算符
*   位与&:两个十进制数转为二进制数从低到高按位运算,同位两个都为1,结果为1,最终将这个二进制数转为十进制得到结果,
*   位或|:两个位都为0结果为0,否则为1
*   异或^:只有两个位不同为1,否则为0 ---> 无进位相加
*   按位取反:一元运算,当前数字转为二进制数,一变0,0变1
位移运算符
*   左移:二元运算符,x<<y,x左移y位,转换为二进制向左移动y位,末尾补0
*   右移:x>>y,转换为二进制,将所有位向右偏移y位,x为非负数则高位补0,x为负数则高位补1,右移一位可看做对x除2,并向下取整

位运算性质 

性质

* 1、交换律可任意交换运算因子的位置,结果不变

* 2、结合律(即(a^b)^c==a^(b^c))

* 3、对于任何数x,都有x^x=0,x^0=x,同自己求异或为0,同0求异或为自己

* 4、自反性A^B^B=A^0=A,连续和同一个因子做异或运算,最终结果为自己

位运算理解(实现加减乘除)

二进制三十二位最高位表示正负。0正,1,负
负数为去掉符号位然后按位取反最后加一

位运算实现加减乘除(在Java虚拟机中用位运算拼凑)
1、加法==>a = a^b   b = (a&b)<<1
 *  异或:无进位相加 
 *  与:进位信息
 *  直到进位信息消失,不进位信息就是结果
2、减法
 *  a加上b的相反数
 *  相反数 ~b
 *  add(a,add(~b,1))
3、乘法
 *  竖式相乘相加
 *  当b= 0 时,直接左移右移,b=1时写a并左右移动
4、除法
 *  将b移动到最接近a的时候,保证不比她大,然后给a减去这个数
 *  a:01101100  b:00001100->01100000
 *  循环操作找到位置为q1的数
public static boolean isNeg(int n){
        return n < 0;
    }
    public static int negNum(int n){
        return add(~n,1);
    }

//加法
 public static int add(int a,int b){
        int sum = a;
        while(b!=0){
            sum = a^b;//无进位相加
            b = (a & b) << 1;//进位信息
            a = sum;
        }
        return sum;
    }

//减法
public static int minus(int a,int b){
        return add(a,negNum(b));
    }

//乘法
public static int multi(int a,int b){
        int res = 0;
        while(b != 0){
            if ((b & 1) != 0){
                res = add(res,a);
            }
            a <<= 1;
            b >>>= 1;
        }
        return res;
    }

//除运算
public static int divide(int a,int b){
        if(a == Integer.MIN_VALUE && b ==Integer.MIN_VALUE){
            return 1;
        }else if(b == Integer.MIN_VALUE){
            return 0;
        }else if(a == Integer.MIN_VALUE){
            if(b == negNum(1)){
                return Integer.MAX_VALUE;
            }else{
                int c = div(add(a,1),b);
                return add(c,div(minus(a,multi(c,b)),b));
            }
        }else{
            return div(a,b);
        }

    }
public static int div(int a,int b){
        int x = isNeg(a)?negNum(a):a;
        int y = isNeg(b)?negNum(b):b;
        int res = 0;
        for (int i = 30; i >= 0; i--) {
            if ((x >> i) >= y){
                res |= (1<<i);
                x = minus(x,y<<i);
            }
        }
        return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
    }

位运算操作

1.2的幂

n = 4 : (n&(n-1)) = 0 是2的幂

n100
n-1011
n&(n-1)000

n = 5 :(n&(n-1)) != 0 不是2的幂

n101
n-1100
n&(n-1)100
public static boolean stack2(int n){
    if(n > 0 && (n & (n - 1)) == 0){
        return true;
    }
    return false; 
}

2.4的幂

 与2的幂与4的幂相同,同时需要加上4的幂%3 = 1

public static boolean stack2(int n){
    if(n > 0 && (n & (n - 1)) == 0 && n % 3 == 1){
        return true;
    }
    return false; 
}

3.不用额外变量两数交换(两个数在内存中是两个独立的地址)

假设 a = 4,b = 5

a100
b101
a = a^b001
b = a^b100
a = a^a101
public static void exch(int a,int b){
        a = a^b;
        b = a^b;
        a = a^a;
    }

4.位1的个数

与2的幂核心代码相同,每次n&(n-1)都会消除1个1

public static int times(int n){
        int t = 0;
        while(n != 0){
            n &= (n-1);
            t++;
        }
        return t;
    }

5.打印某个数的二进制

public static void two(int num){
    for(int i = 31;i >= 1;i--){
        System.out.print((num & (i<<i)) == 0 ? "0":"1");
    }
}

6.数组中只有一个数出现奇数次,求这个数;

int[] arr = new int[]{1,1,2,2,3,3,4,4,5};
int result = 0;
for(int i = 0;i < arr.length;i++){
    result ^= arr[i];
}
System.out.println(result);

7.两种数(出现奇数次的数都为偶数或奇数时会出异常)出现了奇数次,其他数都为偶数次 ,求出现奇数次的两个数;

int[] arr = new int[]{1,1,2,2,3,3,4,4,5,6,6,6};
//result记录两个出现奇数次的数异或的结果
int result = 0;
for(int i = 0;i < arr.length;i++){
    result ^= arr[i];
}
//两个出现了奇数次的数某一位不同时,result的对应那一位就为1,可以根据这个1进行求解
int temp = result & (~result + 1);//求最右边的1,也可以是0
int result1 = 0;
for(int cur : arr){
    if((cur & temp) == 1){
        result1 ^= cur;
    }
}
System.out.println(result1 + " " + (result ^ result1));

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是只菜鸟呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值