位运算

目录

补码

基础知识

按位反

应用举例 

按位与

基础知识

应用举例

按位或

基础知识

应用举例

异或运算

基础知识

应用举例

移位运算

基础知识

应用举例 


清零取位要用与,某位置一可用或,

若要取反和交换,轻轻松松用异或。

补码

基础知识

 

按位反

应用举例 

~0得全为1的掩码,不管机器的字大小是多少。

 

按位与

基础知识

  • 满足交换律、结合律、分配律和德摩根律
  • 0 & A = 0
  • ~0 & A = A
  • A & A = A

应用举例

1、特定位清零

//mask的特定位为0,其他位为1
x & mask

2、取出特定位

//mask的特定位为1,其他位为0
x & mask


取出第k位
x >> k  & 1

3、判断是偶数还是奇数

x & 1 == 0 偶数
x & 1 == 1 奇数

 4、判断一个整数是不是2的幂

boolean power2(int x)
{
    return ((x&(x-1))==0)&&(x!=0);
}

5、取模运算转化成位运算 (在不产生溢出的情况下)

     a % (2^n) 等价于 a & (2^n - 1)

 

按位或

基础知识

  • 满足交换律、结合律、分配律和德摩根律
  • ~0  | A = ~0
  • 0 | A = A
  • A | A = A

应用举例

1、特定位置1

//mask特定位为1,其余位为0
x | mask

2、循环左移和循环右移 

//设sizeof(int)=32
//int型变量循环左移k次
a=a<<k|a>>32-k   

//int型变量a循环右移k次
a=a>>k|a<<32-k  

异或运算

基础知识

  • 满足交换律和结合律,a ^ b = b ^ a,(a ^ b) ^ c = a ^ (b ^ c)
  • 任意数a, a ^ a = 0(偶数个a的异或为0)
  • 任意数a, a ^ 0 = a,结合 a ^ a = 0可得奇数个a的异或为a本身
  • 异或运算就是不带进位的模二加
  • A^B = (A & ~B) | (~A & B)

*拓展

数字电路中还有同或运算,即两个相同为1,不同为0,此处通过用A o B表示

A o B = ~(A ^ B) = (A & B) | (~A & ~B) 

应用举例

1、特定位取反

若想要第k位取反,mask的第k为1,其余位为0

//s = 6   即1010
//若使第3位取反,则mask = 0010

s ^= mask;

2、不借助其他变量交换两个数

//交换x和y的值
void swap(int &a, int &b)
{
    a ^= b;
    b ^= a;
    a ^= b;
}

题:交换数组中心对称的位置的元素。

//若数组为5 2 7 8 3 结果为3 8 3 2 5

void func(int arr[], size_t size)
{
    for (int l = 0, r = size - 1; l < r; ++l, --r)
    {
        *arr[r] = *arr[l] ^ *arr[r];
        *arr[l] = *arr[l] ^ *arr[r];
        *arr[r] = *arr[l] ^ *arr[r];
        }
}

3、不带进位的模二加(不进位加法),以格雷码为例

二进制码转格雷码

转换示意图

g = b ^ (b>>1)

格雷码转二进制码 

转换示意图

4、计算绝对值,利用了模二加

 int abs( int x )
{

             int y ;

             y = x >> 31 ;  //得到全0或全1

             return (x^y)-y ;        //或者 (x+y)^y
 }

5、寻找唯一缺少元素或唯一重复元素

题:给定一个由0, 1, 2, ... , n中n个数组成的序列,每个数字至多出现1次,找出唯一缺失的那个数。

解法1:排序再遍历,时间复杂度为O(NlogN)

解法2:使用HashSet存储出现的元素,在查找0~n,时间复杂度为O(N),空间复杂度也为O(N)。

解法3:使用等差数列前[0, n]的n+1项和,减去当前序列的和,时间复杂度为O(N),但是相加可能出现溢出问题。

解法4:使用异或运算的性质,成对出现的数异或为0,借助数组的索引 

int missNum(int arr[], size_t size)
{
    int res = 0;
    res ^= size;
    for (int i = 0; i < size; ++i)
    {
        res ^= i ^ arr[i];
    }
    return res;
}

*寻找唯一奇数个数的元素解法相同。

 

移位运算

基础知识

C和C++整数分为无符号数和有符号数(默认有符号),Java只有有符号数,java除了左移和右移外,还有无符号右移操作>>>。

C/C++移位操作

左移:对于无符号数,相当于乘2;对于有符号数,左移操作可能改变符号位的值,因此是未定义行为。

右移:对于无符号数,高位补0,相当于除以2,即逻辑右移;对于有符号数,高位补符号位,相当于除以2,即算术右移。

待移位数有w位,移位k位,当k>w时,实际移位为k mod w

应用举例 

1、获得特定位为1的掩码

int mask = (1 << k)

2、获得整数最大值和最小值

int MaxInt = (1 << 31) - 1;
int MinInt = (1 << 31)

3、防止两数取平均加法溢出

 C/C++代码

int low, high;
int mid = unsigned(low + high) >> 1

或者

int avg(int x, int y)   //返回X,Y 的平均值
{   
   return (x&y)+((x^y)>>1);
}

java代码

int low, high;
int mid = (low + high) >>> 1

 不用移位防止溢出的方法

int low, high;
int mid = low + (high - low) / 2  //在high很大,low为负数也有溢出危险

4、转换运算

乘法运算转化成位运算 (在不产生溢出的情况下)

            a * (2^n) 等价于 a<< n

除法运算转化成位运算 (在不产生溢出的情况下)

            a / (2^n) 等价于 a>> n

在编译器的优化中,通常会用加减法运算和左移运算组合代替乘常数,用加减法运算和右移运算组合代替除以常数

如:x*14    转换位(x<<3+(x<<2)+(x<<1)或者(x<<4)-(x<<1)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值