位运算总结

2 篇文章 0 订阅

位操作是各种考试和面试中经常出的题型,在一些算法中使用位运算,不仅能提高效率,而且还能简化代码。

  • 约定1:本文中位操作所涉及的整数均指无符号整数。
  • 约定2:本文中以ALLBIT表示所有位都为1的整数。
  • 约定3:一个整数的最高位在左端,最小位在右端。在计算位的序号时,从右往左数。最低位的序号为1。

位运算符

  • &:与
  • |:或
  • ~:非
  • ^:异或
  • <<:左移
  • >>:右移

集合操作

我们可以用一个整数表示集合,例如一个32位的int型变量,可以表示一个至多有32个成员的集合。某位被设置则表示元素在集合中,否则表示元素不在集合中。


集合的并

A | B

集合的交

A & B

集合的差

A & ~B

集合的补集

~A 或

ALLBIT ^ A

集合中添加第n个元素

A |= 1 << n

集合中删除第n个元素

A &= ~(1 << n)

检查第n个元素是否在集合中

A &  (1 << n)

查找最高位和最低位

最简单也非常高效的方法是在循环中依次测试各位,直到找到1个设置的位为止。

这里有一个查找最低位数值的方法,假设A不为0:A & ~(A - 1)

注意,上面查找的是最低位的数值,而不是最低位的序号。

如果你使用的是gcc编译器,使用gcc编译器的内置函数,可以优化查找最低位最高位的序号。

  • __builtin_ctz:返回低位连续0的个数
  • __builtin_clz:返回高位连续0的个数

注意:不能对0使用这两个gcc内置函数,对于0返回的值是不确定的。

判断一个数是不是2的方幂(判断一个数是不是只有1位被设置)

假定A 不为0,如果A & (A - 1)为0,则说明此数为2的方幂。

计算1的个数

gcc编译器提供了内置函数来完成此任务:

  • __builtin_popcount

如果不能使用此函数。我们可以循环测试每一位,这个效率也不会太慢。当让如果已知1的个数比较少,可以依次清除末尾1的方法。代码如下

int count = 0;
while (A)
{
    ++count;
    A &= (A-1);
}

翻转整数中的位

x = ((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1); // 偶数位右移1位,奇数位左移1位
x = ((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2); // 
x = ((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4);
x = ((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8);
x = ((x & 0xffff0000) >> 16) | ((x & 0x0000ffff) << 16);

算法说明:

  • 第一步,以2位为单位进行分组,交换组内前半部分(只有1位)和后半部分(只有1位)的顺序,则每组内位已经翻转;
  • 第二步,以4位为单位进行分组,交换组内前半部分(有2位)和后半部分(有2位)的顺序,则每组内4位已经翻转;
  • 同理,进行第三、四、五步,在第五步,以32位为1组,交换后,组内位已经完成翻转。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值