zoukankan      html  css  js  c++  java
  • 位运算

    两篇非常好的文章:

    http://blog.csdn.net/zouliping123/article/details/8995373

    http://www.cnblogs.com/flying_bat/archive/2008/06/17/1224178.html

    预备知识

    对于位运算,大家都很熟悉,基本的位操作有与、或、非、异或等等。在面试中经常会出现位运算相关的题,所以我就做了简单的整理,参考了很多写的很好的博客及书籍。

    现在简单说一下,移位运算。

    左移运算:x << y。将x左移y位,将x最左边的y位丢弃,在右边补y个0。

    右移运算:x >> y。将x右移y位,这需要区分x是有符号数还是无符号数。在x是无符号数时,只需将x的最右边的y位丢弃,在左边补上y个0。在x是有符号数时,又分为x是正数还是负数。正数时,同无符号数的处理相同;负数时,将将x的最右边的y位丢弃,在左边补上y个1。

     

    位运算技巧

    计算一个数的二进制中1的个数

    通过与初始值为1的标志位进行与运算,判断最低位是否为1;然后将标志位左移,判断次低位是否为1;一直这样计算,直到将每一位都判断完毕。

     

    [cpp] view plaincopy
     
    1. /* 
    2.     计算一个数的二进制中1的个数 
    3. */  
    4. int countOf1(int num)  
    5. {  
    6.     int count = 0;  
    7.     unsigned int flag = 1;  
    8.   
    9.     while(flag)  
    10.     {  
    11.         if(num & flag)  
    12.         {  
    13.             count++;  
    14.         }  
    15.   
    16.         flag = flag << 1;  
    17.     }  
    18.     return count;  
    19. }  


    还有一种方法,一个整数减一,可以得到该整数的最右边的1变为0,这个1右边的0变为1。对这个整数和整数减一进行与运算,将该整数的最右边的1变为0,其余位保持不变。直到该整数变为0,进行的与运算的次数即为整数中1的个数。

     

     

    [cpp] view plaincopy
     
    1. /* 
    2.     计算一个数的二进制中1的个数 
    3. */  
    4. int countOf1_2(int num)  
    5. {  
    6.     int count = 0;  
    7.   
    8.     while(num)  
    9.     {  
    10.         num = num & (num - 1);  
    11.         count++;  
    12.     }  
    13.     return count;  
    14. }  



     

    判断一个数是否是2的n次方

    一个数是2的n次方,则这个数的最高位是1,其余位为0。根据上一题的第二种解法可以很容易得到解决方案。将这个整数与整数减一进行与运算,如果得到的结果为零,可证明该数为2的n次方。

     

    [cpp] view plaincopy
     
    1. /* 
    2.     判断一个数是否为2的n次方(一个数为2的n次方,则最高位为1,其余位为0) 
    3. */  
    4. bool is2Power(int num)  
    5. {  
    6.     bool flag = true;  
    7.   
    8.     num = num & (num - 1); //计算num和num - 1的与的结果  
    9.     if(num) //如果结果为0,则不是2的n次方  
    10.     {  
    11.         flag = false;  
    12.     }  
    13.       
    14.     return flag;  
    15. }  



     

    整数n经过多少步可以变为整数m

    n和m的异或结果可以得知两数不同位的个数,再调用计算一个数中1的个数的方法,即可得到结果。

     

    [cpp] view plaincopy
     
    1. /* 
    2.     求解n变化为m,需要进行的操作步数 
    3. */  
    4. int countChange(int n,int m)  
    5. {  
    6.     n = n ^ m; //求n和m的异或,再计算结果中1的个数  
    7.     return countOf1_2(n);  
    8. }  



     

    获得最大的int值

     

    [cpp] view plaincopy
     
    1. /* 
    2.     获取最大的int 
    3.     得到结果:2147483647 
    4. */  
    5. int getMaxInt()  
    6. {  
    7.     return (1 << 31) - 1;  
    8. }  
    9.   
    10. /* 
    11.     使用g++编译,出现warning: left shift count is negative 
    12. */  
    13. int getMaxInt_2()  
    14. {  
    15.     return (1 << -1) - 1;  
    16. }  
    17.   
    18. int getMaxInt_3()  
    19. {  
    20.     return ~(1 << 31);  
    21. }  
    22.   
    23. /* 
    24.     在不了解int的长度情况下使用 
    25. */  
    26. int getMaxInt_4()  
    27. {  
    28.     return ((unsigned int) -1) >> 1;   
    29. }  



     

    获得最小的int值

    与获得最大的int方法类似。

     

    [cpp] view plaincopy
     
    1. /* 
    2.     求最小int 
    3.     得到结果:-2147483648 
    4. */  
    5. int getMinInt()  
    6. {  
    7.     return 1 << 31;  
    8. }  
    9.   
    10. /* 
    11.     同样在g++下编译,出现warning: left shift count is negative 
    12. */  
    13. int getMinInt_2()  
    14. {  
    15.     return 1 << -1;  
    16. }  

     

    获得最大的long

     

    [cpp] view plaincopy
     
    1. /* 
    2.     求最大long 
    3.     得到结果:9223372036854775807 
    4. */  
    5. long getMaxLong()  
    6. {  
    7.     return ((unsigned long) -1) >> 1;  
    8. }  

     

    判断一个数的奇偶性

    判断奇偶性,实质是判断最后一位是否是1.

     

    [cpp] view plaincopy
     
    1. /* 
    2.     判断一个数的奇偶性.返回1,为奇数;返回0,为偶数 
    3. */  
    4. bool isOdd(int num)  
    5. {  
    6.     return num & 1 == 1;  
    7. }  



     

    交换两个数(不借助第三变量)

    不用第三个变量交换两个数的方法也有几种,例如a = a + b;  b = a - b; a = a - b。下面这种方法可以实现的基础是一个数m与另一个数n异或,再与n异或,得到的结果是m.

     

    [cpp] view plaincopy
     
    1. /* 
    2.     不适用临时变量,交换两个数 
    3.     a = a ^ b 
    4.     b = b ^ a 
    5.     a = a ^ b 
    6. */  
    7. void mySwap(int* a,int* b)  
    8. {  
    9.     (*a) ^= (*b) ^= (*a) ^= (*b);  
    10. }  



     

    求一个数的绝对值

    下面的方法实现的基础是将n右移31位,可以获得n的符号。

     

    [cpp] view plaincopy
     
    1. /* 
    2.     取绝对值 
    3.     n右移31位,可以获得n的符号。若n为正数,得到0;若n为负数,得到 -1 
    4.      
    5. */  
    6. int myAbs(int n){  
    7.     return (n ^ n >> 31) - (n >> 31);  
    8. }  



     

    求两个数的平均值

    第一种方法较为普遍且简单,不多说了。第二种方法,需要知道的是,( m ^ n ) >> 1得到的结果是m和n其中一个数的有些位为1的值的一半,m & n得到的结果是m 和n都为1的那些位,两个结果相加得到m和n的平均数。

     

    [cpp] view plaincopy
     
    1. /* 
    2.     求m和n的平均数 
    3. */  
    4. int getAverage(int m,int n){  
    5.     return (m + n) >> 1;  
    6. }  
    7.   
    8. /* 
    9.     求m和n的平均数 
    10.     (m ^ n) >> 1 -> 获得m和n两个数中一个数的某些位为1的一半 
    11.     m & n -> 获得m和n两个数中都为1的某些位 
    12. */  
    13. int getAverage_2(int m,int n){  
    14.     return ((m ^ n) >> 1) + (m & n);  
    15. }  



     

    求解倒数第m位相关问题

     

    [cpp] view plaincopy
     
    1. /* 
    2.     获取n的倒数第m位的值(从1开始计数) 
    3. */  
    4. int getMthByTail(int n,int m){  
    5.     return (n >> (m - 1)) & 1;  
    6. }  
    7.   
    8. /* 
    9.     将n的倒数第m位设为1 
    10. */  
    11. int setMthByTail21(int n,int m)  
    12. {  
    13.     return n | (1 << (m - 1));  
    14. }  
    15.   
    16. /* 
    17.     将n的倒数第m位设为0 
    18. */  
    19. int setMthByTail20(int n,int m)  
    20. {  
    21.     return n & ~(1 << (m - 1));  
    22. }  
  • 相关阅读:
    HOG特征提取+python+opencv
    统计模型计算量~pytorch
    CycleGAN训练~训练图像进行拼接
    缺陷检测~分类网络
    缺陷检测~分类网络
    缺陷检测~检测网络
    pytorch中的fc和fc逆操作
    pytorch中的view和view逆操作
    传统的图像特征提取
    TensorFlow安装+入门操作
  • 原文地址:https://www.cnblogs.com/qlky/p/5020646.html
Copyright © 2011-2022 走看看