• java位运算应用


    位移动运算符:


    <<表示左移, 左移一位表示原来的值乘2.


    比如:3 <<2(3为int型) 
    1)把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011, 
    2)把该数字高位(左側)的两个零移出。其它的数字都朝左平移2位, 
    3)在低位(右側)的两个空位补零。则得到的终于结果是0000 0000 0000 0000 0000 0000 0000 1100, 
    转换为十进制是12。


    同理,>>表示右移. 右移一位表示除2.


     


    位运算:


    位运算符包含: 与(&)、非(~)、或(|)、异或(^)


      &:当两边操作数的位同一时候为1时,结果为1,否则为0。如1100&1010=1000   


          | :当两边操作数的位有一边为1时,结果为1。否则为0。如1100|1010=1110   


          ~:0变1,1变0   


          ^:两边的位不同一时候。结果为1。否则为0.如1100^1010=0110


    位运算与位移动执行符的一个场景:


        HashMap的功能是通过“键(key)”可以高速的找到“值”。以下我们分析下HashMap存数据的基本流程: 
        1、 当调用put(key,value)时,首先获取key的hashcode,int hash = key.hashCode(); 
        2、 再把hash通过一下运算得到一个int h. 
    hash ^= (hash >>> 20) ^ (hash >>> 12); 
    int h = hash ^ (hash >>> 7) ^ (hash >>> 4); 
    为什么要经过这种运算呢?这就是HashMap的高明之处。先看个样例。一个十进制数32768(二进制1000 0000 0000 0000),经过上述公式运算之后的结果是35080(二进制1000 1001 0000 1000)。看出来了吗?也许这样还看不出什么,再举个数字61440(二进制1111 0000 0000 0000)。运算结果是65263(二进制1111 1110 1110 1111)。如今应该非常明显了,它的目的是让“1”变的均匀一点。散列的本意就是要尽量均匀分布。


      3、 得到h之后。把h与HashMap的承载量(HashMap的默认承载量length是16,能够自己主动变长。在构造HashMap的时候也能够指定一个长 度。这个承载量就是上图所描写叙述的数组的长度。)进行逻辑与运算,即 h & (length-1),这样得到的结果就是一个比length小的正数。我们把这个值叫做index。事实上这个index就是索引将要插入的值在数组中的 位置。

    第2步那个算法的意义就是希望能够得出均匀的index。这是HashTable的改进,HashTable中的算法仅仅是把key的 hashcode与length相除取余。即hash % length。这样有可能会造成index分布不均匀。

    另一点须要说明,HashMap的键能够为null,它的值是放在数组的第一个位置。




    4、 我们用table[index]表示已经找到的元素须要存储的位置。先推断该位置上有没有元素(这个元素是HashMap内部定义的一个类Entity, 基本结构它包括三个类,key,value和指向下一个Entity的next),没有的话就创建一个Entity<K,V>对象,在 table[index]位置上插入。这样插入结束;假设有的话,通过链表的遍历方式去逐个遍历,看看有没有已经存在的key,有的话用新的value替 换老的value。假设没有。则在table[index]插入该Entity,把原来在table[index]位置上的Entity赋值给新的 Entity的next。这样插入结束。


    以下解说一下原码->反码->补码之间的相互关系


    [-3]反=[10000011]反=11111100 
                 原码            反码
    负数的补码是将其原码除符号位之外的各位求反之后在末位再加1。

     
    [-3]补=[10000011]补=11111101 
                 原码          补码


    也就是说原码转换成补码是先原码  反码 最后+1成补码。位运算都是补码运算的,所以位运算后要再取反+1才得到真正的原码。


    应用举例 
    (1) 推断int型变量a是奇数还是偶数            
    a&1  = 0 偶数 
          a&1 =  1 奇数 
    (2) 取int型变量a的第k位 (k=0,1,2……sizeof(int))。即a>>k&1 
    (3) 将int型变量a的第k位清0。即a=a&~(1 < <k) 
    (4) 将int型变量a的第k位置1, 即a=a ¦(1 < <k) 
    (5) int型变量循环左移k次,即a=a < <k ¦a>>16-k  (设sizeof(int)=16) 
    (6) int型变量a循环右移k次,即a=a>>k ¦a < <16-k  (设sizeof(int)=16) 
    (7)整数的平均值 
    对于两个整数x,y,假设用 (x+y)/2 求平均值。会产生溢出。由于 x+y 可能会大于INT_MAX,可是我们知道它们的平均值是肯定不会溢出的。我们用例如以下算法: 
    int average(int x, int y)  //返回X,Y 的平均值 
    {    
        return (x&y)+((x^y)>>1); 

    (8)推断一个整数是不是2的幂,对于一个数 x >= 0,推断他是不是2的幂 
    boolean power2(int x) 

        return ((x&(x-1))==0)&&(x!=0)。 

    (9)不用temp交换两个整数 
    void swap(int x , int y) 

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

    (10)计算绝对值 
    int abs( int x ) 

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

    (11)取模运算转化成位运算 (在不产生溢出的情况下) 
            a % (2^n) 等价于 a & (2^n - 1) 
    (12)乘法运算转化成位运算 (在不产生溢出的情况下) 
            a * (2^n) 等价于 a < < n 
    (13)除法运算转化成位运算 (在不产生溢出的情况下) 
            a / (2^n) 等价于 a>> n 
            例: 12/8 == 12>>3 
    (14) a % 2 等价于 a & 1        
    (15) if (x == a) x= b; 
                else x= a; 
            等价于 x= a ^ b ^ x; 
    (16) x 的 相反数 表示为 (~x+1)




    实例


        功能              ¦          演示样例            ¦    位运算 
    ----------------------+---------------------------+-------------------- 
    去掉最后一位          ¦ (101101->10110)          ¦ x >> 1 
    在最后加一个0        ¦ (101101->1011010)        ¦ x < < 1 
    在最后加一个1        ¦ (101101->1011011)        ¦ x < < 1+1 
    把最后一位变成1      ¦ (101100->101101)          ¦ x ¦ 1 
    把最后一位变成0      ¦ (101101->101100)          ¦ x ¦ 1-1 
    最后一位取反          ¦ (101101->101100)          ¦ x ^ 1 
    把右数第k位变成1      ¦ (101001->101101,k=3)      ¦ x ¦ (1 < < (k-1)) 
    把右数第k位变成0      ¦ (101101->101001,k=3)      ¦ x & ~ (1 < < (k-1)) 
    右数第k位取反        ¦ (101001->101101,k=3)      ¦ x ^ (1 < < (k-1)) 
    取末三位              ¦ (1101101->101)            ¦ x & 7 
    取末k位              ¦ (1101101->1101,k=5)      ¦ x & ((1 < < k)-1)
    取右数第k位          ¦ (1101101->1,k=4)          ¦ x >> (k-1) & 1


    把末k位变成1          ¦ (101001->101111,k=4)      ¦ x ¦ (1 < < k-1) 
    末k位取反            ¦ (101001->100110,k=4)      ¦ x ^ (1 < < k-1) 
    把右边连续的1变成0    ¦ (100101111->100100000)    ¦ x & (x+1) 
    把右起第一个0变成1    ¦ (100101111->100111111)    ¦ x ¦ (x+1) 
    把右边连续的0变成1    ¦ (11011000->11011111)      ¦ x ¦ (x-1) 
    取右边连续的1        ¦ (100101111->1111)        ¦ (x ^ (x+1)) >> 1 
    去掉右起第一个1的左边 ¦ (100101000->1000)        ¦ x & (x ^ (x-1)) 
    推断奇数      (x&1)==1 
    推断偶数 (x&1)==0       


    比如求从x位(高)到y位(低)间共同拥有多少个1


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

  • 相关阅读:
    Spring Boot2 系列教程(二十)Spring Boot 整合JdbcTemplate 多数据源
    Spring Boot 如何给微信公众号返回消息
    Spring Boot2 系列教程(十九)Spring Boot 整合 JdbcTemplate
    Spring Boot2 系列教程(十八)Spring Boot 中自定义 SpringMVC 配置
    Spring Boot 开发微信公众号后台
    Spring Boot2 系列教程(十七)SpringBoot 整合 Swagger2
    Spring Boot2 系列教程(十六)定时任务的两种实现方式
    Spring Boot2 系列教程(十五)定义系统启动任务的两种方式
    Spring Boot2 系列教程(十四)CORS 解决跨域问题
    JavaScript二维数组
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/6958943.html
Copyright © 2020-2023  润新知