位运算初步入门&&状态压缩操作

位运算

程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作

位运算的用处很多,也很强大。

首先再学习位运算之前,我们先复习以下,编码知识

 

在计算机中,正数是直接用原码表示的,如5,在计算机中就表示为:0000 0101。

负数用补码表示,如-5,在计算机中表示为1111 1011。

 

原码  反码 补码问题

原码:将一个整数,转换成二进制,就是其原码。

如:3的二进制是 0000 0011 原码就是0000 0011  -3的原码是 1000 0011

反码:正数的反码就是其原码;负数的反码是将原码中,除符号位以外,每一位取反

如 3的反码是 0000 0011   -3的反码是 1111 1100

补码:正数的补码就是其原码;负数的反码+1就是补码

如 3的补码是 0000 0011   -3的补码是1111 1101

 

 

位运算:

& 按位与操作

相同位的两个数字都为1,则为1;若有一个不为1,则为0。

       3&5          3:       0000 0011

                        5:       0000 0101

                        &————————

                    3&5         0000 0001

|  按位或操作

相同位只要一个为1即为1。

            3|5       3:       0000 0011

                        5:       0000 0101

                        |————————

                    3|5:        0000 0111

^按位异或操作 

  规则:两个数对应位相同 运算结果为0  对应位不同 运算结果为1

              3^5    3:       0000 0011

                        5:       0000 0101

                        ^————————

                     3^5         0000 0110

性质:异或运算满足结合律和交换律

           满足消去律  a^b=b^c  则a=c

           a^a=0   (a^b)^b=0

           所以 交换两个数的方法可以这么写:

void swap(int a,int b)
{
     a=a+b;
     b=a-b;
     a=a-b;
}
void swap(int a,int b)
{
    a=a^b;
    b=a^b;
    a=a^b;
}

~按位取反

~是一个单目运算符 作用是对二进制每一位数取反

                        3  0000 0011

                     ~3  1111 1100

*例如 -1在计算机里的补码是 1111 1111

                                所以 ~(-1)=0000 0000 =0

所以ACM中经常看到 while(~scanf("%d",&a))   代表 scanf返回-1(即EOF)时结束

 

<<左移运算符              >>右移运算符

<<左移  按照指定的位数将一个数的二进制数值向左移位   左移后 低位补0 移除的高位舍弃

>>右移  按照指定的位数将一个数的二进制数值向右移位   移除的低位舍弃  如果是无符号数则高位补0  若有符号 则高位补符号或者补0(不同处理器不一样)

如  a=-8  内存中补码为1111 1000

则a>>2=-2     右移两位后为  1111 1110   为-2

 

状态压缩

这是位运算的一个重要应用

比如 一个迷宫  1代表墙  0代表可以走   通常我们用二维数组存迷宫 做BFS或DFS

那么  迷宫不大的时候 我们可以用二进制数来表示这个迷宫

我们可以把n*m的迷宫  每一行表示为一个m位的二进制数  那么n个整数 就可以表示这个迷宫了

同样的  如果n*m不大的话   我们也可以把整个迷宫 表示为一个n*m位的二进制数

而迷宫的各种操作  我们可以借助位运算来完成  如下表

(切记  位运算的优先级很低! 使用的时候 一定记得带上括号)

去掉最后一位  (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))
取末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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1900_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值