学习记录番外 位运算

基础语法

位运算针对整型数据转化成二进制按位操作,计算速度快于其他运算操作。在进行位运算时要注意类型转换,double和float要显式强转成int等,而char等“小整型”会自动隐式转换为int型,或更大。由于部分位运算对有符号整型(的符号位)的操作依赖于本地计算机系统,会带来极大不确定性,故一般之应用于无符号整型。位运算均遵循左结合律,优先级高于逻辑运算符,低于比较运算符,且从高到低依次为&、^、| 。注意不要把位运算和逻辑运算混淆(例如&和&&不是一回事)。

(以下假定char8位,int32位)

~位取反(~expr)

每一位都取反。(0变1,1变0)注意一般用于无符号整型。

eg. unsigned char bits =0227 【10010111】

变成【11111111,11111111,11111111,01101000】(先提升成int再按位取反).

<<左移(expr1<<expr2)

左侧操作数exper1为被移动数,右侧操作数exper2为移动位数(以十进制来表达,必定为正数),补位用0,因为移动是按二进制来计算的,所以移动k位实际上就是变成原来的2的k倍。(右移就是1/2的k次方)(在不超出类型范围限制的情况下,如果超限直接被移除出去).要特别注意,如果原数是负数,那么原数左侧的补位有可能是0或1,由本地计算机决定。

eg. unsigned char bits=0233(八进制) 【10011011】

exper<<8变成【00000000,00000000,10011011,00000000】

>>右移(expr1>>expr2)

操作类似左移,看例子(沿用上面的)。

exper>>3变成【00000000,00000000,00000000,00010011】

&位与(exper1&exper2)

&、|、^均是针对转化成二进制的整型数据的两数对应的每一位进行操作。

&:1&1=1,else=0;

|:0|0,else=1;

^:1^0=1,0^1=1,else=0;(相同为0,相异为1

eg. unsigned char exper1 =0145【01100101】,

      unsigned char exper2 =0257【10101111】.

exper1&exper2变成【前位为零,00100101】

|位或(exper1|exper2)

exper1|exper2变成【前位为零,11101111】

^位异或(exper1^exper2)

exper1^exper2变成【前位为零,11001010】
强转(慎用)

type (expr);//函数式强转

(type) expr;//c风格强转

只知道知识是没用的,刷题练一下。这篇文章我会时常维护,不定期加入一些自己的思考和补一些题。

简单技巧

&运算通常用于二进制取位操作

例如一个数&1的结果就是取出二进制最末位,而配合左移运算,可以取出任意一位:x&(1<<(k-1))。
| 运算通常用于二进制特定位上的无条件赋值:

例如一个数|1的结果就是把二进制最末位强行变为1,如果需要把二进制最末位变成0,对这个数 |1之后再减一就可以了,其实际意义就是把这个数强行变成最近接的偶数。配合左移运算,可以对任意一位进行同种操作。
^运算通常用于对二进制的特定一位进行取反操作:

^运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即x^y^y=x;

^运算可以用于简单的加密,比如原始值int a = 19880516;密钥 int key =1314520; 进行加密 int data=key^a = 20665500;解密 data^key == a;
^运算还可以实现两个值的交换而不需要中间变量,例如:
 

///先看加减法中交换实现
void swap(long int &a,long int &b)

{

     a = a+b;

     b = a-b;

     a = a-b;

}
///b=a^b^b==a;  a=a^b^a==b;
void swap(long int &a,long int &b)

{

    a = a^b;

    b = a^b;

    a = a^b;

}


~运算全部取反:

~会把内存中的0和1全部取反,所以要格外小心,你需要注意整数类型有没符号,如果~的对象是无符号整数(不能表示负数),那么他的值就是它与它的上界限的之差,因为无符号类型的数是用0000到FFFF依次表示的。

左右移运算用于调取和乘除:

通常认为a<<1比a*2更快,因此程序中乘以2的操作尽量用左移一位来代替。
且我们经常用>>1来代替 /2(div 2),比如二分查找、堆的插入操作等等(gcd中用除以2(>>1)操作来代替慢的出奇的%(mod)运算可以极大提高效率)。想办法用>>代替除法运算可以使程序的效率大大提高。

左右移运算配合其他位运算可以实现对某一特定二进制位的操作。

具体应用

去掉最后一位    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->101101,k=3    x & ~(1<<(k-1))
右数第k位取反    101001->101101,k=3    x ^ (1<<(k-1))
取末三位    1101101->101    x &7
取末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的左边    100101000->1000    x&(x^(x-1))

&1取二进制末位:

应用:判定奇偶

           &1为1是奇数,&1为0为偶数

x&(x-1) 消去最后一位有效1

应用1:O(1)时间判断某个数是否是2的幂

              2的幂的二进制表示只有最高位是1。如果x&(x-1)为0 则是2的幂,反之不是。

 应用2:计算在一个 32 位的整数的二进制表示中有多少个 1

              循环使用x&(x-1)并计数。

应用3:计算将整数A转换为B,需要改变多少个bit位

              即计算A和B有多少位是不同的,先A^B,异或后相同为0,不同为1。问题转化成A^B二进制表示中有多少个 1。

二进制子集枚举:

给定可数集,枚举所有子集:每个元素都有选(1)和不选(0)两种状态,用二进制记录与表示。

x^y^y=x:

(1^1^1=1 0^0^0=0 1^0^0=1 0^1^1=0)

用于特殊集合不重元素求取。

参考

https://blog.csdn.net/wuguai4/article/details/7311953

https://blog.csdn.net/deaidai/article/details/78167367

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值