Skip to content

Latest commit

 

History

History
105 lines (71 loc) · 2.53 KB

Bit_operation.md

File metadata and controls

105 lines (71 loc) · 2.53 KB

位运算

1. 位运算使用技巧

  1. 基本位运算操作,与、或、异或、非,左右移(其中左右移常用于快速乘除法)。以及简单的用位运算判断奇偶,取负等。
&, |, ^, ~, <<, >>
  1. 位运算交换两个数,用到偶数个元素异或为0的特性,这里即a^b^b=a,a^a^b=b, 代码表示为
void swap(int& a, int& b) {
  a = a ^ b;
  b = b ^ a;		// b = b ^ a ^ b = a
  a = a ^ b;		// a = a ^ b ^ a = b
}
  1. 求最大的2的整次幂数x & (-x)
  • 从位运算的角度来看,x & (-x) = x & (~x + 1),即将x的二进制数,只留下最右侧的1,其余全为0,因此这样的操作可以用来求不大于x的2的整次幂数
  • 这样的操作在树状数组中常用来求lowbit
  1. 高低位变换, 如16位无符号数,要求将其高8位和低8位进行交换,可以如下处理:
unsigned short x = 34520
x = (x >> 8) | (x << 8)
  1. 二进制逆序
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. 将最右边的1变为0n & (n-1)
  2. 统计二进制中1的个数 ,使用6中的技巧,可以如下处理:
int cnt = 0;
while (n) {
  n = n & (n - 1);
  cnt++;
}

2. 状态压缩中常用的位运算技巧

  1. 要求集合中不能有两个相邻的元素
if ((mask >> 1) & mask) continue;
  1. 在限定必须不取某些元素的前提下枚举子集
// 限定mask的某些位必须不在集合中
// mask中某一位为0表示这一位必须不在子集中
for (int subset = mask; subset > 0; subset = (subset - 1) & mask)
  1. 在限定必须取某些元素的前提下枚举子集
// 限定mask的某些位必须在集合中
// mask中某一位为1表示这一位必须在集合中
for (int subset = mask; subset < (1 << m); subset = (subset + 1) | mask)
  1. 找出二进制中恰好含有k个1的所有数
for (int mask = 0; mask < (1 << n);) {
  int tmp = mask & (-mask);
  mask = (mask + tmp) | (((mask ^ (mask + tmp)) >> 2) / tmp);
}

3. 位运算中的计算技巧

  • 位运算中只有以下两种情况满足分配律
  • A & (B | C) = (A & B) | (A & C)
  • (A & B) ^ (A & c) = A & (B ^ C)

参考