位运算技巧集

位运算技巧集

  1. 一般用0xfffffff这种16位数,代替32位二进制数;
  2. Java中的幂指数运算不能是^ ,这个符号代表的是异或运算符;
  3. &|~^ 与或非异或
  4. 两个大于号 向右移位运算
  5. 一般可以通过先将需要处理的数字变为二进制数,在观察数字,运算和最终结果之间和关系。如果需要处理和数字有两个,可以观察两个数字的组合又什么规律。比如,通过拼接,异或,与运算得出某个数,推导这个数和最终结果有什么关系。
for(i:=31;i>=0;i--){
	1<<i;
}

0010000
0001000
0000100
0000010
0000001
  1. 以上代码可以用来按位比较对应的bit,最大不超过32bit,因为每次循环对1进行移位操作后结果的值如上。
n = 100000
n-1 = 011111
n & n-1 = 0


n = 101000
n-1 = 100111
n & n-1 = 100000
  1. 所以只要在n不为0的时候每次对n与n-1进行&操作就可以消掉最右侧的一个1。
  2. 左移一位乘2,右移一位除2 。
  3. 特殊数字(其实很多(lll¬ω¬)·······)奇数位偶数位啥的有需要自己算吧

0x55555555
01010101010101010101010101010101

0x33333333
00110011001100110011001100110011

0x0f0f0f0f
00001111000011110000111100001111

这0和1还不一边长 (lll¬ω¬)

  1. 前n位和后n位进行或操作可前后换位,这要建立在其他位都是0的情况下才有效,这样才能确实保证是和0操作,否则其它位移动后和0或,又多一位。(非常经典的高低位交换)
a = (a >> 8) | (a << 8);
  1. Java 没有无符号数哦

  2. 位操作进行二进制逆序将无符号数的二进制表示进行逆序,求取逆序后的结果。

    如数34520的二进制表示:
    10000110 11011000
    逆序后则为:
    00011011 01100001
    

它的十进制为7009在字符串逆序过程中,可以从字符串的首尾开始,依次交换两端的数据。在二进制中使用位的高低位交换会更方便进行处理,这里我们分组进行多步处理。

归并:
(右移n位|左移n位)
下面这个方法,找数字是非常繁琐的,底下有更好的。

第一步:以每 2 位为一组,组内进行高低位交换

交换前: 10 00 01 10 11 01 10 00
交换后: 01 00 10 01 11 10 01 00

第二步:在上面的基础上,以每 4 位为 1 组,组内高低位进行交换

交换前: 0100 1001 1110 0100
交换后: 0001 0110 1011 0001

第三步:以每 8 位为一组,组内高低位进行交换

交换前: 00010110 10110001
交换后: 01100001 00011011

第四步:以每16位为一组,组内高低位进行交换

交换前: 0110000100011011
交换后: 0001101101100001

对于上面的第一步,依次以 2 位作为一组,再进行组内高低位交换,这样处理起来比较繁琐,下面介绍另外一种方法进行处理。

先分别取原数 10000110 11011000 的奇数位和偶数位,将空余位用 0 填充:原数: 10000110 11011000
奇数位: 10000010 10001000
偶数位: 00000100 01010000
再将奇数位右移一位,偶数位左移一位,此时将两个数据相或即可以达到奇偶位上数据交换的效果:

原数:  10000110 11011000
奇数位右移一位: 0 10000010 1000100
偶数位左移一位:0000100 01010000 0
两数相或得到: 01001001 11100100

上面的方法用位操作可以表示为:
取a的奇数位并用 0 进行填充可以表示为:
a & 0xAAAA
取a的偶数为并用 0 进行填充可以表示为:
a & 0x5555

因此,上面的第一步可以表示为:
a = ((a & 0xAAAA) >> 1) | ((a & 0x5555) << 1)
同理,可以得到其第二、三和四步为:
a = ((a & 0xCCCC) >> 2) | ((a & 0x3333) << 2)
a = ((a & 0xF0F0) >> 4) | ((a & 0x0F0F) << 4)
a = ((a & 0xFF00) >> 8) | ((a & 0x00FF) << 8)
因此整个操作为:unsigned short a = 34520;

a = ((a & 0xAAAA) >> 1) | ((a & 0x5555) << 1);
a = ((a & 0xCCCC) >> 2) | ((a & 0x3333) << 2);
a = ((a & 0xF0F0) >> 4) | ((a & 0x0F0F) << 4);
a = ((a & 0xFF00) >> 8) | ((a & 0x00FF) << 8);
  1. x^x=0;
    x^0=x;
    数组中,只有一个数出现一次,剩下都出现两次,找出出现一次的数
  2. if(n & 1 == 1) 判断奇数偶数
  3. a ^ b 无进位加法
  4. a & b 进位标志

Java中均为补码

正数的原码、反码、补码相同。

负数的反码是原码除最高位的取反,补码是反码+1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值