300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 位运算常用技巧总结

位运算常用技巧总结

时间:2022-09-10 11:18:50

相关推荐

位运算常用技巧总结

基础知识

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

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

左移运算: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;然后将标志位左移,判断次低位是否为1;一直这样计算,直到将每一位都判断完毕。

/*计算一个数的二进制中1的个数*/int countOf1(int num){int count = 0;unsigned int flag = 1;while(flag){if(num & flag){count++;}flag = flag << 1;}return count;}

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

/*计算一个数的二进制中1的个数*/int countOf1_2(int num){int count = 0;while(num){num = num & (num - 1);count++;}return count;}

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

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

/*判断一个数是否为2的n次方(一个数为2的n次方,则最高位为1,其余位为0)*/bool is2Power(int num){bool flag = true;num = num & (num - 1); //计算num和num - 1的与的结果if(num) //如果结果为0,则不是2的n次方{flag = false;}return flag;}

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

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

/*求解n变化为m,需要进行的操作步数*/int countChange(int n,int m){n = n ^ m; //求n和m的异或,再计算结果中1的个数return countOf1_2(n);}

4、获得最大的int值

/*获取最大的int得到结果:2147483647*/int getMaxInt(){return (1 << 31) - 1;}/*使用g++编译,出现warning: left shift count is negative*/int getMaxInt_2(){return (1 << -1) - 1;}int getMaxInt_3(){return ~(1 << 31);}/*在不了解int的长度情况下使用*/int getMaxInt_4(){return ((unsigned int) -1) >> 1; }

5、获得最小的int值

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

/*求最小int得到结果:-2147483648*/int getMinInt(){return 1 << 31;}/*同样在g++下编译,出现warning: left shift count is negative*/int getMinInt_2(){return 1 << -1;}

6、获得最大的long

/*求最大long得到结果:9223372036854775807*/long getMaxLong(){return ((unsigned long) -1) >> 1;}

7、判断一个数的奇偶性

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

/*判断一个数的奇偶性.返回1,为奇数;返回0,为偶数*/bool isOdd(int num){return num & 1 == 1;}

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

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

/*不适用临时变量,交换两个数a = a ^ bb = b ^ aa = a ^ b*/void mySwap(int* a,int* b){(*a) ^= (*b) ^= (*a) ^= (*b);}

9、求一个数的绝对值

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

/*取绝对值n右移31位,可以获得n的符号。若n为正数,得到0;若n为负数,得到 -1*/int myAbs(int n){return (n ^ n >> 31) - (n >> 31);}

10、求两个数的平均值

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

/*求m和n的平均数*/int getAverage(int m,int n){return (m + n) >> 1;}/*求m和n的平均数(m ^ n) >> 1 -> 获得m和n两个数中一个数的某些位为1的一半m & n -> 获得m和n两个数中都为1的某些位*/int getAverage_2(int m,int n){return ((m ^ n) >> 1) + (m & n);}

11、求解倒数第m位相关问题

/*获取n的倒数第m位的值(从1开始计数)*/int getMthByTail(int n,int m){return (n >> (m - 1)) & 1;}/*将n的倒数第m位设为1*/int setMthByTail21(int n,int m){return n | (1 << (m - 1));}/*将n的倒数第m位设为0*/int setMthByTail20(int n,int m){return n & ~(1 << (m - 1));}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。