使用异或运算实现两处内存的原地值交换
2015-03-23 12:57
351 查看
^(异或运算)与|(或)和&(与)的一个显著的不同点在于,异或运算能够保存两个位串一种关系,举个简单的例子,比如对于a=10,b=01这两个二进制数来说,他们的异或结果为11, 从这个结果上我们就可以非常直观地得出a与b在两个位上的都是“相异”的,所以如果我们知道了两个位串的异或结果(也就是两个位串的关系),和其中的一个位串,我们就能根据它们之间的关系来推导出另一个位串的结果,这个结果是确定的,比如我们知道a是10,而异或结果是11,那么我们可以推导出b只能为01。而同样对于a和b,其按位与的结果是00,假如又知道a的值为10,那么b的值即可能是00,也可能是01,也就是说b是不能确定的。同样的或运算也是不能推导出确定的b的值的。
对于异或运算,有(a^b)^a=b,可以这样理解,a^b的结果我们可以记成一个结果R,R的每一位依赖于a和b两个位串每位的异同,如果a与b的某一位相同,那么R对应的位置0,反之置1。假如,我们现在知道了R也知道了a:
1. 对于R和a对应的每一位,如果R中的位值是0,如果a的这一位上的值是0,那么R与a在这一位上的异或结果位0,如果a在这一位中的值是1,那么R与a在这一位上的异或结果是1,总的来说如果R上的某位是0,那么与a对应位的值的异或值总是与a相同的,根据异或的定义,b对应的位上的值就是R与a对应位的异或结果;
2. 考虑第二种情况,如果R中的位置时1,如果a的这一位上的值是0,那么R与a在这一位上的异或结果是1,如果a在这一位中的值是1,那么1^1=0,总的来说,如果R上的某位是1时,那么与a对应位的值的异或结果总是与a不同的,根据异或的定义,R与a的异或结果成功地还原了b中对应位的值。
综合考虑以上两种情况,我们可以得到(a^b)^a=b。利用异或运算的这种临时保存状态的计算特性,我们可以利用其实现内存中的两个值的交换过程,当然这样做,除了会节省一点儿内存空间外,在性能上未必有太大的差别。
我们分析一下以上函数体中的三行程序:
1. 第一次的*y = *x ^ *y,这次运算将x,y两个指针所指向的32位(int表示为4个字节)的内存的每一位的关系信息保存到了y所指向的32位长的内存上。这时x所指向的内存的值依旧是原来的值。
2. 第二次的 *x = *x ^ *y 可以扩展为*x = *x ^ (*x ^ *y) = *y(此*y就是y所指向内存的最初的值),所以,这行程序执行完成后,x所指向的内存的值,就变成了最初y所指向的内存的值,而此时的y所指向的内存值,依旧是*x,*y异或的结果,也就是x与y内存段的关系信息。
3. 此时的x段的内存段的值已经是最初y内存段的值了,同样根据第二步的原理,我们根据最初的y内存段的值,和x与y内存段的关系就可以推导出最初的x内存段的值,最后将其值赋予y内存段,这样y内存段就被最初的x内存段的值覆盖了。
经过以上的三步,x与y两个内存段,就在没有中间内存帮助的条件下,实现了原地值的交换,其原理就是利用了异或运算的确定性,也就是通过a,b,R中的任何两个,就可以推导出另外一个。
对于异或运算,有(a^b)^a=b,可以这样理解,a^b的结果我们可以记成一个结果R,R的每一位依赖于a和b两个位串每位的异同,如果a与b的某一位相同,那么R对应的位置0,反之置1。假如,我们现在知道了R也知道了a:
1. 对于R和a对应的每一位,如果R中的位值是0,如果a的这一位上的值是0,那么R与a在这一位上的异或结果位0,如果a在这一位中的值是1,那么R与a在这一位上的异或结果是1,总的来说如果R上的某位是0,那么与a对应位的值的异或值总是与a相同的,根据异或的定义,b对应的位上的值就是R与a对应位的异或结果;
2. 考虑第二种情况,如果R中的位置时1,如果a的这一位上的值是0,那么R与a在这一位上的异或结果是1,如果a在这一位中的值是1,那么1^1=0,总的来说,如果R上的某位是1时,那么与a对应位的值的异或结果总是与a不同的,根据异或的定义,R与a的异或结果成功地还原了b中对应位的值。
综合考虑以上两种情况,我们可以得到(a^b)^a=b。利用异或运算的这种临时保存状态的计算特性,我们可以利用其实现内存中的两个值的交换过程,当然这样做,除了会节省一点儿内存空间外,在性能上未必有太大的差别。
void swap(int *x, int *y) { *y = *x ^ *y; *x = *x ^ *y; *y = *x ^ *y; }
我们分析一下以上函数体中的三行程序:
1. 第一次的*y = *x ^ *y,这次运算将x,y两个指针所指向的32位(int表示为4个字节)的内存的每一位的关系信息保存到了y所指向的32位长的内存上。这时x所指向的内存的值依旧是原来的值。
2. 第二次的 *x = *x ^ *y 可以扩展为*x = *x ^ (*x ^ *y) = *y(此*y就是y所指向内存的最初的值),所以,这行程序执行完成后,x所指向的内存的值,就变成了最初y所指向的内存的值,而此时的y所指向的内存值,依旧是*x,*y异或的结果,也就是x与y内存段的关系信息。
3. 此时的x段的内存段的值已经是最初y内存段的值了,同样根据第二步的原理,我们根据最初的y内存段的值,和x与y内存段的关系就可以推导出最初的x内存段的值,最后将其值赋予y内存段,这样y内存段就被最初的x内存段的值覆盖了。
经过以上的三步,x与y两个内存段,就在没有中间内存帮助的条件下,实现了原地值的交换,其原理就是利用了异或运算的确定性,也就是通过a,b,R中的任何两个,就可以推导出另外一个。
相关文章推荐
- 使用异或运算实现两数交换
- 使用异或运算实现两数交换
- 深入理解异或运算 xor 的含义——再探不使用加减乘除实现加法运算、不使用额外空间交换两个变量的值
- C++使用异或运算实现交换两个数的值
- 在不借助第三方变量情况下实现两个变量的交换(借助于异或运算)
- 异或运算实现两个数的交换
- 用异或运算实现两个数字的交换(装x)
- 异或运算及其在交换变量值中的使用
- 使用异或运算对交换两个变量的数据
- java 使用异或运算交换
- Java使用异或运算实现简单的加密解密算法实例代码
- 异或运算实现两个数的交换
- 通过异或运算实现两个变量的交换(不需借助第三个变量)
- 使用异或运算 不借助临时变量交换两个数
- 异或运算实现两个数的交换
- 两个变量值交换 异或运算实现方法
- 使用异或运算实现菜单项功能的启用与关闭
- 不使用第三个参数和库函数实现两个数字的交换(异或的妙用)
- 为什么异或运算可以实现两个整数的交换,而无需借助第3个临时变量
- java中把两个变量进行值交换,通过异或两次运算就能实现值互换。