美文网首页
Java位运算小节

Java位运算小节

作者: fd490e4f570d | 来源:发表于2019-02-01 10:16 被阅读0次

    2019新春支付宝红包技术大揭秘在线峰会将于03-07日开始,点击这里报名届时即可参与大牛互动。

    位运算表达式由操作数和位运算符组成,实现对整数类型的二进制数进行位运算。位运算符可以分为逻辑运算符(包括~、&、|和^)及移位运算符(包括>>、<<和>>>)。

    
    1)左移位运算符(<<)能将运算符左边的运算对象向左移动运算符右侧指定的位数(在低位补0)。
    
    2)“有符号”右移位运算符(>>)则将运算符左边的运算对象向右移动运算符右侧指定的位数。 “有符号”右移位运算符使用了“符号扩展”:若值为正,则在高位插入0;若值为负,则在高位插入1。
    
    3)Java也添加了一种“无符号”右移位运算符(>>>),它使用了“零扩展”:无论正负,都在高位插入0。这一运算符是C或C++没有的。
    
    4)若对char,byte或者short进行移位处理,那么在移位进行之前,它们会自动转换成一个int。 只有右侧的5个低位才会用到。这样可防止我们在一个int数里移动不切实际的位数。 若对一个long值进行处理,最后得到的结果也是long。此时只会用到右侧的6个低位,防止移动超过long值里现成的位数。 但在进行“无符号”右移位时,也可能遇到一个问题。若对byte或short值进行右移位运算,得到的可能不是正确的结果(Java 1.0和Java 1.1特别突出)。 它们会自动转换成int类型,并进行右移位。但“零扩展”不会发生,所以在那些情况下会得到-1的结果。
    
    

    在进行位运算时,需要注意几点:

    
    (1)>>>和>>的区别是:在执行运算时,>>>运算符的操作数高位补0,而>>运算符的操作数高位移入原来高位的值。
    
    (2)右移一位相当于除以2,左移一位(在不溢出的情况下)相当于乘以2;移位运算速度高于乘除运算。
    
    (3)若进行位逻辑运算的两个操作数的数据长度不相同,则返回值应该是数据长度较长的数据类型。
    
    (4)按位异或可以不使用临时变量完成两个值的交换,也可以使某个整型数的特定位的值翻转。
    
    (5)按位与运算可以用来屏蔽特定的位,也可以用来取某个数型数中某些特定的位。
    
    (6)按位或运算可以用来对某个整型数的特定位的值置1。
    
    

    位运算符的优先级

    
    ~的优先级最高,其次是<<、>>和>>>,再次是&,然后是^,优先级最低的是|。
    
    

    位运算的应用

    1.判断int型变量a是奇数还是偶数

    
    a&1 == 0 偶数
    
    a&1 == 1 奇数
    
    

    2.求平均值,比如有两个int类型变量x、y,首先要求x+y的和,再除以2,但是有可能x+y的结果会超过int的最大表示范围。

    
     (x&y)+((x^y)>>1);
    
    
    
    知识点:>>n 相当于除于2^n ,<<n 相当于乘于2^n 。
    
    x,y对应位均为1,相加后再除以2还是原来的数,如两个00001000相加后除以2仍得00001000,那么我们把x与y分别分成两个部分来看,两者相同的位分别拿出来 则 :
    
    x = (111111111111000)2 = (111111111111000)2 + (000000000000000)2
    
    y = (111111111111010)2 = (111111111111000)2 + (000000000000010)2
    
    相同部分我们叫做x1,y1,不同部分我们叫做x2,y2.那么现在(x+y)/2 =(x1+y1)/2 +(x2 + y2)/2 ,因为x1 == y1 ,所以(x1+y1)/2 ==x1 ==y1,相同部分我们用与运算求出来 x1 = x&y ,不同部分的和我们用^求出来,然后除于2就是我们想要的结果了。
    
    

    3.对于一个大于0的整数,判断它是不是2的几次方

    
     ((x&(x-1))==0)&&(x!=0);
    
     /*如果是2的幂,n一定是100... n-1就是1111....
    
      所以做与运算结果为0*/
    
    

    4.比如有两个int类型变量x、y,要求两者数字交换,位运算的实现方法

    
     x ^= y;
    
     y ^= x;
    
     x ^= y;
    
    

    5.求绝对值

    
     int abs( int x ) {
    
     int y ;
    
     y = x >> 31 ;
    
     return (x^y)-y ; //or: (x+y)^y
    
     }
    
    

    6.取模运算,采用位运算实现

    
     a % (2^n) 等价于 a & (2^n - 1) ;或者 m % n 等价于 m & (n-1)
    
    

    7.乘法运算 采用位运算实现

    
     a * (2^n) 等价于 a << n
    
    

    8.除法运算转化成位运算

    
     a / (2^n) 等价于 a>> n
    
    

    9.求相反数

    
     (~x+1)
    
    

    10.a % 2 等价于

    
     a & 1
    
    

    11.取int型变量a的第k位 (k=0,1,2……sizeof(int))

    
     a>>k&1 (先右移再与1)
    
    

    12.将int型变量a的第k位清0

    
     a&~(1<<k) (10000 取反后为00001 )
    
    

    13.将int型变量a的第k位置1

    
     a|(1<<k)
    
    

    14.int型变量循环左移k次

    
     a<<k|a>>16-k (设sizeof(int)=16)
    
    

    15.int型变量a循环右移k次

    
     a>>k|a<<16-k (设sizeof(int)=16)
    
    

    16.对于一个数 x >= 0,判断是不是2的幂。

    
     boolean isPower2(int x) {
    
     return ((x&(x-1))==0) && (x!=0);
    
     }
    
    

    17.不用temp交换两个整数

    
     void swap(int x , int y) {
    
     x ^= y;
    
     y ^= x;
    
     x ^= y;
    
     }
    
    

    18.条件判断赋值简写

    
     if (x == a)
    
     x= b;
    
       else
    
     x= a;
    
      等价于 x= a ^ b ^ x;
    
    

    19.x的相反数

    
     (~x+1)
    
    

    20.m乘以2的n次方

    
     m << n
    
    

    21.m除以以2的n次方

    
     m >> n
    
    

    22.求整数k从x位(高)到y位(低)间共有多少个1

    
    public static int findChessNum(int x, int y, int k) {
    
     int result = 0;
    
     for (int i = y; i <= x; i++) {
    
     result += ((k >> (i - 1)) & 1);
    
     }
    
     return result;
    
     }
    
    

    23.取绝对值

    
     int abs(int n){
    
     return (n ^ (n >> 31)) - (n >> 31);
    
     }
    
    /* n>>31 取得n的符号,若n为正数,n>>31等于0,若n为负数,n>>31等于-1
    
    若n为正数 n^0=0,数不变,若n为负数有n^-1 需要计算n和-1的补码,然后进行异或运算, 结果n变号并且为n的绝对值减1,再减去-1就是绝对值 */
    
    

    24.只出现一次的数字

    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

    说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

    示例 1:

    
    输入: [2,2,1]输出: 1
    
    

    示例 2:

    
    输入: [4,1,2,1,2]输出: 4
    
    

    这个题首先想到的就是异或的特性。相同的数字异或的结果为 0,那么出现奇数次的一定就是最后我们想要的结果。

    
    public int singleNum(int[] nums){
    
     int res = num[0];
    
     for(int i=1;i<nums.length;i++){
    
     res ^= nums[i];
    
     }
    
     return res;
    
    }
    
    

    总结

    333.png

    点击阅读更多,查看更多详情

    相关文章

      网友评论

          本文标题:Java位运算小节

          本文链接:https://www.haomeiwen.com/subject/kdwrsqtx.html