0
点赞
收藏
分享

微信扫一扫

位运算的巧妙使用 -- 交换两个值

引言

我们都知道,在程序代码中,位运算的计算时间是比较短的,相比加减法乘除法来说,所以,我们经常会在内核代码,或者一些要求运算速度的场景中看到使用位运算的,接下来就介绍两个位运算的巧妙运用吧。

不使用多余的空间交换两个值

考虑一个 swap 函数,它可以将 a 与 b 的值进行交换,我们可以写出使用指针的版本:

template <typename T>
void swap(T *a, T *b){
T temp = *a;
*a = *b;
*b = temp;
}

这样看我们其实使用了一个局部变量 temp,那么我们能否在不使用局部变量的情况下实现两个数值的交换呢?我们先来看看第一种简单的方法,使用加减法:

int a = 1;
int b = 2;
//swap by +/-
a = a + b;
b = a - b; //b = (a + b) - b = a
a = a - b; //a = (a + b) - b = (a + b) - a = b

可以发现,这种方法实际上是先将 a+b 赋值给 a,再计算 b(实际上要给 b 赋值之前 a 的值),所以用 a-b 就得到了旧的 a 值,同理,最后一步 a=a-b 也计算出了 b 的值,达成了交换的目的。

第二种方式是使用异或运算,我们首先来看下异或运算(两位相异为 1,相同为 0)的基本规则: 0 ^ 0 = 0, 0 ^ 1 = 1, 1 ^ 0 = 1, 1 ^ 1 = 0

运算律(异或运算的本质,统计对应位上面的 1 的奇偶个数,奇数为 1,偶数为 0): 归零律,即 a^a=0 恒等律,即 a^0=0 交换律,即 a^b=b^a------实际运算过程只与每位相关,0^1 = 1^0 = 1,交换律成立 结合律,即(a^b)^c = a^(b^c)------同样地,考虑三个数分别为 000,001,...111 进行验证, 自反律,即 a^b^a = b(实际上就是两个 a 做异或统计的 1 的个数都为偶数个了) 这样,我们来看看如下的代码交换

int a = 1;
int b = 2;
//swap by ^
a = a ^ b;
b = a ^ b; //b = (a ^ b) ^ b = a ^ (b ^ b) = a ^ 0 = a;
a = a ^ b; //a = (a ^ b) ^ a = a ^ b ^ a = b;

可以看见,在第二步运用结合律,归零律,恒等律,b = a; 第三步运用自反律,a = b。

举报

相关推荐

0 条评论