位运算(以C语言为例)

本篇博文部分思路及图表来自MoreWindows博客,原文链接:https://blog.csdn.net/MoreWindows/article/details/7354571

本文所涉及操作均以C语言为例,以下操作仅能对整型数据使用。

注意:位运算优先级较低,为保证正确,建议添加括号。

符号描述运算规则
&两位都为1时,结果才为1
|两位都为0时,结果才为0
^异或两位相同为0,不同为1
~按位取反唯一的单目运算符,将0变1,1变0
<<左移左移若干位,高位丢弃,低位补0
>>右移右移若干位,对无符号数,高位补0

不同编译器对有符号数的右移运算处理方法不一样(在Dev C++中负数也是直接除以2

注意:进行左移时,请保证移动的位数小于变量占用的bit的数量。以int型(32bit,取值范围为 [ − 2 31 , 2 31 − 1 ] [-2^{31} , 2^{31}-1] [231,2311])为例,左移31位,即1<<31 = 2^31,部分编译器会令变量wrap out成-2^31,但有些编译器会直接报错,因此保险起见最多左移30位

接下来介绍部分位运算技巧


乘除

右移n位,即原始值除以 2 n 2^n 2n,左移n位,原始值乘以 2 n 2^n 2n

int a=10, b=10;
a <<= 2;
b >>= 2;

a左移2位,即a的值乘以 2 2 2^2 22,也就是乘以4,即40。
b右移2位,即b的值除以 2 2 2^2 22,也就是除以4,即2。

取符号位

判断变量的符号:

int sign = a >> 31; 

(a为int型,有32位,右移31位即可得到符号位,若a<0,则sign为-1,其他则为0)。如果a右移31位后的值赋值给布尔型变量,则a<0时布尔值为1,其他为0。

取任意位

取得变量a的第p位(从右往左数,最右边为第0位),赋值给b。

int b = a >> p & 1; 

若a的第p位为0,则b为0,否则为1。

实际上还有一种方法:

int b = a & (1 << p); 

但该方法没有上一种好,当a的第p位为0时,b为0。当a的第p位为1时,b并非为1,而是随着p变化(等于 2 p 2^p 2p)。

将任意位置为0或1

a |= 1 << p;    //将变量a的第p位(从右往左数)置为1
b &= ~(1 << p); //将变量b的第p位(从右往左数)置为0

模拟开关

由于“~”是按位取反,因此对于值为True(也就是00000001)的bool型变量,取反后变成11111110,还是True。因此要模拟开关,需使用异或操作。

bool s = 0;
s = 1^s;   //每执行一次,就会从0变1,或从1变0。

取相反数

int signReverse = ~a+1;

由于计算机使用原码、反码、补码的方式存储数据,int范围内所有数字按位取反后加1都等于其相反数。除了 − 2 31 -2^{31} 231,它按位取反加1后等于自己。

上述两种方法结合,可以写出一种非常高端的取绝对值的函数:

int GetAbs(int a)
{
    int t=a>>31;
    return (a^t)-t;
} 

用t取得a的符号位,任何数与0异或值不变,与1异或值取反,之后若a为负数 再减去-1,即加1。
(该方法同样对-2^31无效)

两数交换

void Swap(int a, int b)  
{  
    a ^= b;  
    b ^= a;  
    a ^= b; 
}  

异或满足交换律,且一个数对另一个数连续异或两次,得到它自己。(即a^b^b==a)

这里放一道比较有意思的题:LeetCode 136

题目链接:https://leetcode.com/problems/single-number/

数组中有n个元素,除了其中的一个元素,其他每个元素会在数组中出现两次。找出这个特殊的元素(该元素仅在数组中出现一次)。

常规思路1:排序后查找相邻的数(时间复杂度为 O ( n ∗ l o g 2 ( n ) ) O(n*log_2(n)) O(nlog2(n))

常规思路2:直接扫一遍列表计算每个数出现的次数(时间复杂度为 O ( n ) O(n) O(n)但数组会很大)

位运算的思路:0与任意数字a连续异或两次,值仍为0,若只异或一次,值为a。

int singleNumber(int* a, int n){
    int ans = 0;
    for (int i=0; i<n; i++) 
        ans ^= a[i];
    return ans;
}

判断是否为2的次方

LeetCode 231

bool isPowerOfTwo(int n){
    return n > 0 && (n & (n - 1)) == 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值