实用的位操作

284 阅读3分钟

本文主要介绍一些实用的位操作。参考自labuladong, 很厉害的大佬,大家可以关注他的微信公众号labuladong。

0、利用异或(^)性质

异或性质: 设数n, 则n^n=0, n^0=n。并且异或满足交换律和结合律。

使用场景:

思路:首先将数组扩展一位,同时将该位赋值为0,之后对所有数组下标和元素进行异或,得到了结果即为缺失的值。

例如一个长度为9的数组[0,1,3,4,5,6,7,8,9], 将其扩展为[0,1,3,4,5,6,7,8,9,0],然后对数组元素和下标进行异或,即0^0^1^1^2^3^3^4^4^5...8^9^9^0,得到结果2即为缺失值

1、使用或(|)操作和空格(' ')将英文字符转化成小写

('a' | ' ') = 'a'
('A' | ' ') = 'a'

2、使用与(&)操作和下划线将英文字符转化成大写

('b' & '_') = 'B'
('B' & '_') = 'B'

3、利用异或(^)操作和空格进行英文字符大小写转换

('d' ^ ' ') = 'D'
('D' ^ ' ') = 'd'

原理:每个字符在ASCII码表中都对应了一个数字,而通过这些位运算恰好能够将该字符对应的数字转换成另外的字符对应的数字,从而将该字符转换成另外的字符。

4、判断两个整数是否符号位是否相同

int x = -1, y = 2;
bool f = ((x ^ y) < 0); // true
int x = 3, y = 2;
bool f = ((x ^ y) < 0); // false

原理:利用了计算机中使用补码表示的特点,负数的符号位为1,正数的符号位为0,异或之后如果原来两数符号位相同则结果数(res)的符号位为0,表示正数,即res>0;否则符号位为1,表示负数,即res<0。

Note: 读者可能会认为可以使用两束相乘或者相除的方式判断,其实不然,因为这种处理方式存在结果溢出的风险。

5、交换两个数

int a = 1, b = 2;
a ^= b;
b ^= a;
a ^= b;
// 现在 a = 2, b = 1

6、n&(n-1) 算法题常用!!!

作用:将数字n的二进制表示中最后一位1变为0

以下是n、n-1和n&(n-1)的二进制表示,可以很清晰的看到n&(n-1)是如何实现该功能的。

1)算法题一:计算数字n的二进制表示中存在几个1?

int hammingWeight(int n) {    
    int res = 0;    
    while (n != 0) { 
    // 0的二进制补码形式为所有位都是0       
        n = n & (n - 1);        
        res++;    
    }   
    return res;
}

2)算法题二:判断一个数是不是2的指数

前置知识:如果某个数为2的指数,那么该数的二进制表示只存在一个1

bool isPowerOfTwo(int n) {    
    if (n <= 0) return false;    
    return (n & (n - 1)) == 0; // 如果对运算符优先级不清楚,建议像这里一样加上括号()
}

想了解更多位运算黑科技的朋友看这里:graphics.stanford.edu/~seander/bi…

这是一个外国网站,收集了非常多的位操作用法。