您的位置:首页 > 其它

不使用第三个变量交换两个变量的值之"异或"的实际应用

2014-12-03 22:25 344 查看
本文通过对不使用第三变量替换两个变量的值,从而深入讲解异或在实际中的使用,让您对异或的强大作用了熟于心.

本文为原创,转载请注明出处,谢谢;

作者:飞哥


一.首先我们使用第三变量的方法

这是我们通常在程序中使用的方法.

例如:

void ExchangeValue(int& a,int& b)
{
int t;
t = a;
a = b;
b = t;
}


以上方法简单易懂,便于程序阅读,但其借用了第三变量。


二.通过算术运算方式交换

例如:

void ExchangeValue(int& a,int& b)
{
a = b-a;
b = b-a;
a = b+a;
}


可以这样理解:
1)把a、b看做数轴上的两个点,

2) 第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;
3) 第二句“b=b-a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;
4) 第三句“a=b+a”求出b到原点的距离(a到原点距离与ab两点距离之和),并且将其保存在a中。完成交换。

缺点:只能用于数字类型,字符串之类的就不可以了。

三.通过位运算方式交换

例如:

void ExchangeValue(int& a,int& b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
如果您不理解该函数,请继续向下看,如果您已经明白了,那您可以离开略过该文章了...

3.1)异或概念巧解

有很多人对异或的概念有时候总是模糊不清,在此我解释一下该概念:
1)"或"的概念相信大多程序员都立马能想到,那么可以把"异或"的概念和"或"概念放在一起理解:
"或" : 两个位数相"或",只要其中一个位为1则结果为1;
"异或" : 通常可以按照 "或"来计算,与"或"唯一的不同是只有当两个位全为1时,其值为0;
2)"异或"教科书中概念 :当两个位计算时,如果位相同则为0,如果不同则为1。
如果您用以上概念时,偶尔突然说起这个异或,可能大脑还要转一圈才能反应过来,所以我一般按照第一种方式理解

3.2)异或的常用属性

1) 1 ^ X = X(反码);
1与任何数异或,结果为该数反码;
2) 0 ^ X = X(本身);
0与任何数异或,结果为该数本身;
3) a ^ b ^ b = a;
任何一个数连续两次和同一个数异或结果为其本身;

通过以上所有知识点相信您已经对上诉通过位运算交换两个值得例子了如指掌!

四.异或的面试题详解

4.1)面试题1

题目:

1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;

不用辅助存储空间,能否设计一个算法实现?

答案:
方法一 : 将所有数加起来,减去1+2+...+1000的和。

方法二 : 将所有的数全部异或,得到的结果与1^2^3^...^1000的结果进行异或,得到的结果就是重复数。

下面对方法二进行证明:

证明:

1)假设n为重复数,同时假设1~1000各个数异或结果为T,即:

1^2^...^n^...^1000 = T; //这里1~1000中该重复数n只包含了一个;

2)异或满足交换律,所以将数组中所有数相互间进行异或,结果:

1^2^...^n^...^n^...^1000 = 1^2^...^n^...1000 ^ n= T ^ n;

3)异或满足结合律,其次,对于任何数X,都有 X ^ X = 0; X ^ 0 = X;

所以有以下结果:

T ^ (T ^ n) = T ^ T ^ n = 0 ^ n = n;

所以,将所有的数全部异或,得到的结果与1到1000所有数进行异或的结果进行异或,得到的结果就是重复数。

4.2)面试题2

题目: 一个数组存放若干整数,一个数出现奇数次,其余数均出现偶数次,找出这个出现奇数次的数?

提示: 数字出现偶数次,那立刻联想到: X ^ X = 0; 即:对于所有出现偶数次的数字全部异或一遍,其结果为: 0;

再次联想到: X ^ 0 = X; 那么答案相信您已经明白了。

答案: 将所有的数做异或操作,其结果即为出现奇数次的数字;

4.3)面试题3

题目: 请给出使用比 if(a == b) 效率更快捷的方法判断两个变量是否相等

答案: if( a ^ b == 0) ,利用了异或的性质:任何数与自己异或为0;

4.4)面试题4

题目: 在一个超级大的数组中存放两部分数据,一部分数据有重复且重复个数为偶数,一部分数据没有重复,找出没有重复的所有数据;
--该题目为本人根据百度一道面试题改编,比原题稍微复杂点;

答案: 首先贴出代码如下:
void Output(int* szData,int nSize)
{
int nSameNum = 0;
for (int i = 0; i < nSize; i++)
{
nSameNum = 0;
for (int j = 0 ; j < nSize; j++)
{
if ( (i ^ j) &&  ( szData[i] ^ szData[j] ) == 0)
nSameNum++;
}
if (nSameNum <= 0)
printf("数组中只出现过一次的值为: %d",szData[i]);
}
}
对以上代码解释如下:
1)其主要应用了异或的特性: X ^ X = 0;
利用该特性判断两个值是否相等;
2) 该函数通过对每个数与其他所有的数相比较(这里的比较使用了异或性质) , 如果有相同的数据则个数加1,最后判断其相同数据的总个数是否大于0,
如果小于等于0则表示没有相同的数据,将其输出去;
所以,该题目即使修改为: 找出数组中无重复的数据也可以;

4.5)面试题五

题目: 找出一个数组中无重复的数据;
答案: 同4.4;

以上文章为本人开篇之作,请各位码界大佬多多指教!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: