位运算练习

作者: w_左拖拖 | 来源:发表于2017-05-23 17:00 被阅读0次

位运算直接对在内存中的二进制数据进行处理,因此处理数据的速度非常快,巧妙的运用位运算可以使程序更简洁和高效。

C中基本的位运算包含&,|,,^,<<,>>,其中取反()是单目运算,其余为双目运算,java中多了一个无符号右移>>>,最高位的符号位不参与补位。我们知道最高位表示这个数的符号0为正数,1为负数,>>位移会将高位的空缺补成符号位。下图以byte为例

无符号右移.jpg 所以求int最大值可以使用(1<<31)-1,也可以使用-1>>>1这里就利用了无符号右移技巧。

练习题:
房间有32盏灯,需要实现以下功能:
1.打开某盏灯
2.关闭某盏灯
3.打开所有灯
4.关闭所有灯
5.指定下标返回此灯的状态
要求:使用最小的存储空间。
很多人拿到这个题直接定义一个boolean数组或int数组,但是仔细想想开和关两个状态可以使用一个bit位来保存,int正好32位,所以用1个int就可以处理了。

class Light {
    int l; // 用一个int保存32盏灯的状态
}

1、打开某盏灯,即将该位置设1。1或上0,1均为1,所以我们只需将1移到指定的位置然后求或即可。


No.1.jpg

代码如下:

/**
 * 打开某盏灯
 * @param i 下标1~32
 */
public Light turnOn(int i) {
    l |= (1 << i - 1);
    return this;
}

2、关闭某盏灯,即将该位置设0。


No.2.jpg

代码如下:

/**
 * 关闭某盏灯
 * @param i 下标1~32
 */
public Light turnOff(int i) {
    l &= ~(1 << i - 1);
    return this;
}

3、打开或关闭所有盏灯,即将所有位设1。上面无符号右移的图中可知-1的二进制是全1所以我们可以使用l|-1,但晕个-1是个魔数无意思可以将-1换成~0变成l|~0,还可以使用异或(XOR)相同为0,不同为1,一个数XOR自己将得到0,那XOR自己的反则得到1于是可以写成l^~l

/**
 * 打开所有灯
 */
public Light turnOnAll() {
    l ^= ~l; // 或 l |= ~0 或 l |= -1
    return this;
}
/**
 * 关闭所有灯
 */
public Light turnOffAll() {
    l ^= l; // 或 l &= 0
    return this;
}

5、指定下标返回此灯的状态,这个比较简单把这个位右移到首位然后与1即可

/**
 * 返回指定灯的状态
 * @param i 下标1~32
 */
public int statusOf(int i) {
    return l >>> (i - 1) & 1;
}

下面是完整代码附测试代码

static class Light {
    int l; // 用一个int保存32盏灯的状态

    /**
     * 打开某盏灯
     * @param i 下标1~32
     */
    public Light turnOn(int i) {
        l |= (1 << i - 1);
        return this;
    }

    /**
     * 关闭某盏灯
     * @param i 下标1~32
     */
    public Light turnOff(int i) {
        l &= ~(1 << i - 1);
        return this;
    }

    /**
     * 打开所有灯
     */
    public Light turnOnAll() {
        l ^= ~l; // 或 l |= ~0 或 l |= -1
        return this;
    }

    /**
     * 关闭所有灯
     */
    public Light turnOffAll() {
        l ^= l; // 或 l &= 0
        return this;
    }

    /**
     * 返回指定灯的状态
     * @param i 下标1~32
     */
    public int statusOf(int i) {
        return l >>> (i - 1) & 1;
    }

    /**
     * 打印,将int转为2进制格式输出
     */
    public void println() {
        int charPos = 32;
        int var = l;
        char[] buf = new char[charPos];
        for (int i = 0; i < buf.length; i++) {
            buf[i] = '0';
        }
        do {
            buf[--charPos] += (var & 1);
            var >>>= 1;
        } while (var != 0 && charPos > 0);
        System.out.println(new String(buf));
    }
}

测试代码

    public static void main(String[] args) {
        // TEST
        Light l = new Light();
        l.turnOn(1).println();
        l.turnOn(10).println();
        l.turnOff(1).println();
        l.turnOffAll().println();
        l.turnOnAll().println();
        l.turnOff(32).turnOff(12).println();
        System.out.println(l.statusOf(10));
        System.out.println(l.statusOf(12));
    }

位运算的优先级较低要记得写括号,不然会造成意想不到的后果。

相关文章

网友评论

    本文标题:位运算练习

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