位运算小结

基础

我们假设 a = 1000110 1 ( 2 ) , b = 0010011 1 ( 2 ) a=10001101_{(2)}, b=00100111_{(2)} a=10001101(2),b=00100111(2)
为了表示方便下面的数统一用二进制表示(如果是其他形式会标注)

a&b

&——按位与,将a和b每个二进制位与,如

a a a1000 1101
b b b0010 0111
a & b a\And b a&b0000 0101

即 :

0 & 0 = 0 0\And 0=0 0&0=0 0 & 1 = 0 0\And 1=0 0&1=0
1 & 1 = 1 1\And 1 = 1 1&1=1 1 & 0 = 0 1\And 0=0 1&0=0

a|b

|——按位或,将a和b每个二进制位或,如

a a a1000 1101
b b b0010 0111
a ∣ b a\mid b ab1010 1111

即 :

0 ∣ 0 = 0 0\mid 0=0 00=0 0 ∣ 1 = 1 0\mid 1=1 01=1
1 ∣ 1 = 1 1\mid 1 = 1 11=1 1 ∣ 0 = 1 1\mid 0=1 10=1

a^b

^——按位异或,将a和b每个二进制位异或
其实异或这玩意就是(~a & b)|(a &~b),如:
|——按位或,将a和b每个二进制位或,如

a a a1000 1101
b b b0010 0111
a ∧ b a \land b ab1010 1010

即 :

0 ∧ 0 = 0 0\land 0=0 00=0 0 ∧ 1 = 1 0\land 1=1 01=1
1 ∧ 1 = 0 1\land 1 = 0 11=0 1 ∧ 0 = 1 1\land 0=1 10=1

~a

~——按位取反,将a的每个二进制位按位取反,如:

a a a1000 1101
∼ a \sim a a0111 0010

即 :

∼ 0 = 1 \sim 0=1 0=1 ∼ 1 = 0 \sim1=0 1=0

a<<k

<<——左移运算符,将a左移k个二进制位,相当于乘以 2 k 2^k 2k

a a a1000 1101
a ≪ 2 a\ll 2 a20011 0100

可以看出高位被移出去了,即溢出

即 :

1 ≪ 2 = 100 1\ll 2=100 12=100 0 ≪ 2 = 0 0\ll2=0 02=0

a>>k

相当于除以 2 k 2^k 2k

算数右移(考虑符号位)

每一次右移的最高位按当前符号位填充

a a a1000 1101 − 11 5 ( 10 ) -115_{(10)} 115(10)
a ≫ 2 a\gg 2 a21110 0011 − 2 9 ( 10 ) -29_{(10)} 29(10)

逻辑右移(不考虑符号位)

最高位直接填充0

a a a1000 1101 14 1 ( 10 ) 141_{(10)} 141(10)
a ≫ 2 a\gg 2 a20010 0011 3 5 ( 10 ) 35_{(10)} 35(10)

数字都给你们了,简单除一下就能验证了
我们都知道计算机内部二进制最高位为符号位,且用补码表示
看起来逻辑右移好像有一丢丢不靠谱,可爱的小a酱逻辑右移两位最高位都变了||ヽ( ̄▽ ̄)ノミ|Ю
所以,我们聪明的编译器当然会做一些小处理撒:

数据类型为unsigned时,为逻辑右移
数据类型为signed时,为算数右移

应用

交换两数

a ^= b;
b ^= a;
a ^= b;

让我们小小的分析一下⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄
设x=a,y=b;

a ^= ba = a ^ ba = x ^ y
b ^= ab = a ^ bb = x ^ y ^ y = x
a ^= ba = a ^ ba = x ^ y ^ x = y

当然这只是秀下技巧,实际效率反而没有直接交换两数高哦(^ ^)

位运算加法

a = ( a n a n − 1 . . . a 2 a 1 a 0 ) ( 2 ) a=(a_n a_{n-1}...a_2 a_1 a_0)_{(2)} a=(anan1...a2a1a0)(2)
b = ( b n b n − 1 . . . b 2 b 1 b 0 ) ( 2 ) b=(b_n b_{n-1}...b_2 b_1 b_0)_{(2)} b=(bnbn1...b2b1b0)(2)
c = ( c n c n − 1 . . . c 2 c 1 c 0 ) ( 2 ) c=(c_nc_{n-1}...c_2c_1c_0)_{(2)} c=(cncn1...c2c1c0)(2)
c i c_i ci a i a_i ai b i b_i bi 的进位
我们很容易看出第 c i + 1 c_{i+1} ci+1 a i , b i , c i a_i,b_i,c_i ai,bi,ci推出

核心代码:

    while (b) {
        int r = (a&b) << 1;
        a ^= b;
        b = r;
    }

快速幂

戳一下ヾ(◍°∇°◍)ノ゙
里面的普通版就是快速幂啦

数组中唯一出现过一次的数

找数组中唯一出现过一次的数,数据保证数组其他数出现有且仅有两次
♪(^ ∇^*)把数组中所有数都异或一下,返回异或和
我们知道1 ^ 1 = 0, 0 ^ 0 = 0,也就是一个数与自己异或结果为0,那最终答案就是与0异或,是自己本身。
可以继续推广一下:

一个数奇数次异或为自己本身,偶数次异或为0

线性基

使n个整数异或和最大,时间复杂度 O ( n ) O(n) O(n)
传送门

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值