使用异或的方式交换两个变量在Java数组中的陷阱

Manjusaka1990 2017-04-24 01:23:55
交换两个变量,有很多种方法,就不一一介绍了.
大多数人首先能想到的方法是定义一个临时变量,
如下:
int a = 5;
int b = 10;

int temp = a;
a = b;
b = temp;
此结果就是a = 10,b = 5;
这种方法虽然使用到一个临时变量,性能上可能稍微弱了一点点(达不到显著水平),但是交换数据很安全,可读性也非常高,推荐使用这种方法.

然而一些喜欢体现自己是技术大神的同学,喜欢使用异或进行交换,如下:

int a = 10;
int b = 20;

a = a ^ b;
b = a ^ b;
a = a ^ b;
此时的结果 a = 20; b = 10;
这个方法使用了异或的特性,本身不会有什么问题,由于操作的是二进制进行运算,也没有定义新的变量,理论上性能会高一些,
当然,还可以装大神,显示自己技术大牛,然而它也是有缺陷的,可读性就比较差.

写到这里,异或的方法如果仅仅是可读性差,那么也没必要说它有什么陷阱了.可是真的是这样的吗?
这里的陷阱还需要从选择排序说起.
我们都知道,选择排序的底层实现是这样的:

public static void sort(int[] arr){
for (int i = 1;i <= arr.length - 1 ;i++){
int minindex = i-1;
for (int j = i; j <= arr.length - 1; j ++ ){
if (arr[minindex] > arr[j]){
minindex = j;
}
}
int temp = arr[i -1];
arr[i -1] = arr[minindex];
arr[minindex] = temp;
}
}

习惯使用异或来交换的话就觉得理所当然可以这样写:
public static void sort(int[] arr){
for (int i = 1;i <= arr.length - 1 ;i++){
int minindex = i-1;
for (int j = i; j <= arr.length - 1; j ++ ){
if (arr[minindex] > arr[j]){
minindex = j;
}
}
arr[i -1] = arr[i -1] ^ arr[minindex];
arr[minindex] = arr[i -1] ^ arr[minindex];
arr[i -1] = arr[i -1] ^ arr[minindex];
}
}

假如你是这样认为,那么恭喜你进入了陷阱!
输入数组
int[] arr = {1,4,4,7,8,9,5,4,6};
结果输出竟然变成这样:
[0, 0, 0, 4, 5, 6, 7, 0, 9]
what???

分析结果就知道其原因,并不是因为使用异或的方法不能进行交换,而是因为数组的索引问题带来的!
选择排序原理是将第一个元素假设为最小的一个元素,然后它与之后的元素进行比较,小于这个元素的元素,
就记录最小元素的索引位置,然后将当前最小的元素继续与之后的元素进行比较,直到一轮比较完毕,
再将获得的最小值与假设的最小值位置进行交换.

这样有可能会出现假设的元素就是实际的最小元素,那么在一轮比较下来,出现
minindex = i - 1,而不是minindex = j;

在minindex = i - 1情况下,
假如i = 1简化一下就是:
arr[0] = arr[0] ^ arr[0];
arr[0] = arr[0] ^ arr[0];
arr[0] = arr[0] ^ arr[0];
看到这里,你应该就明白了,索引是0的元素竟然是在异或它本身,而我们知道,变量异或它本身,结果是0啊!
因此使用异或写选择排序,需要判断当前索引有没有改变,即:
if (minindex != i-1){
arr[i -1] = arr[i -1] ^ arr[minindex];
arr[minindex] = arr[i -1] ^ arr[minindex];
arr[i -1] = arr[i -1] ^ arr[minindex];
}
一路分析到这里,我想你也能看出这个陷阱了.

总结就是:
装大神,使用异或交换两个变量是有风险的,技术没学到家会翻车的!
所以我推荐使用第一种方法,简单明了,可读性好,于己于人都有利.
...全文
278 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
ageovb 2020-03-28
  • 打赏
  • 举报
回复 1
我就是写快速排序的时候翻车了,还在想怎么会是0
LangRenSheng 2019-08-02
  • 打赏
  • 举报
回复
亲身体验,开始还一脸懵。
李德胜1995 2017-04-24
  • 打赏
  • 举报
回复
强势围观。。。
自由自在_Yu 2017-04-24
  • 打赏
  • 举报
回复
一剑侵心 2017-04-24
  • 打赏
  • 举报
回复
专家啊,学习了
《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。 目 录 第1部分C++ 多线程系统编程 第1章线程安全的对象生命期管理3 1.1当析构函数遇到多线程. . . . . . . . . . . . . . . . .. . . . . . . . . . . 3 1.1.1线程安全的定义. . . . . . . . . . . . . . . . .. . . . . . . . . . . 4 1.1.2MutexLock 与MutexLockGuard. . . . . . . . . . . . . . . . . . . . 4 1.1.3一个线程安全的Counter 示例.. . . . . . . . . . . . . . . . . . . 4 1.2对象的创建很简单. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 5 1.3销毁太难. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 7 1.3.1mutex 不是办法. . . . . . . . . . . . . . . . . . . .. . . . . . . . 7 1.3.2作为数据成员的mutex 不能保护析构.. . . . . . . . . . . . . . 8 1.4线程安全的Observer 有多难.. . . . . . . . . . . . . . . . . . . . . . . . 8 1.5原始指针有何不妥. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 11 1.6神器shared_ptr/weak_ptr . . . . . . . . . .. . . . . . . . . . . . . . . . 13 1.7插曲:系统地避免各种指针错误. . . . . . . . . . . . . . . . .. . . . . . 14 1.8应用到Observer 上.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.9再论shared_ptr 的线程安全.. . . . . . . . . . . . . . . . . . . . . . . . 17 1.10shared_ptr 技术与陷阱. . . .. . . . . . . . . . . . . . . . . . . . . . . . 19 1.11对象池. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 21 1.11.1enable_shared_from_this . . . . . . . . . . . . . . . . . . . . . . 23 1.11.2弱回调. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 24 1.12替代方案. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 26 1.13心得与小结. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 26 1.14Observer 之谬. . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 第2章线程同步精要 2.1互斥器(mutex). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.1.1只使用非递归的mutex . . . . . . . . . . . . . .. . . . . . . . . . 33 2.1.2死锁. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 35 2.2条件变量(condition variable). . . . . . . . . .

67,512

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧