一、异或的性质
异或的概念还是比较好理解:相同为0,不同为1。不过以前对异或的性质却没有较为深入的了解。
1、异或操作满足交换律和结合律:a^b=b^a; a^b^c=a^(b^c);
2、0与任何变量异或,结果为这个变量:a=0^a;
3、任何变量与其自己异或,结果为0:0=a^a;
举个例子:如果要交换两个变量的值,一般的方法是需要定义一个中间变量,然后交换两个变量的值;但是也可以用异或的操作交换两个变量的值,如下所示:
#include<stdio.h>
int main(void)
{
int a=1;
int b=2;
a=a^b;
b=a^b;/*把上式带入:b=a^b^b=a*/
a=a^b;/*把上式带入:a=a^b^a=b*/
printf("%d,%d",a,b);
return 0;
}
不需要中间变量,仅用异或的操作就交换了两个变量的值。不过在用这种方法前,必需确保两个变量位于不同的存储位置:比如交换a和a的值,会把a变成0。所以这种方式是一种小聪明,并不提倡。
二、做两个题
1、一个数组中,只有一个变量出现了奇数次,其余变量都出现了偶数次,求出现奇数次的这个变量。
#include<stdio.h>
int exor(int array[],int length);
int main(void)
{
int a;
int array1[7]={1,2,3,2,3,1,5};
a=exor(array1,7);
printf("%d",a);
}
int exor(int array[],int length)
{
int odd=0;
int i;
for(i=0;i<length;i++)/*异或遍历数组,出现奇数次的变量经过异或遍历为变量本身,出现偶数次的变量经过异或遍历为0*/
{
odd^=array[i];
}
return odd;
}
2、一个数组,只有两个变量出现了奇数次,其余变量都出现了偶数次,求这两个出现了奇数次的变量。
int exor(int array[],int length)
{
int eor=0;
int one=0;
int elseone;
int i,c;
for(i=0;i<length;i++)/*假设两个出现奇数次的变量为a和b,异或遍历数组,得到两个变量异或后的结果:a^b*/
{
eor^=array[i];
}
/*因为a,b肯定不相等,所以a^b肯定不为0,所以enr肯定有一位为1,通过这一位,将数组分类,a,b属于不同的类*/
c=((~eor)+1)&eor;/*通过取反加一,再与原值相与,得到c为:enr最右侧不为0的位保留,其余位都置0*/
for(i=0;i<length;i++)
{
if((array[i]&c)==0)
{
one^=array[i];
}
}
elseone=one^eor;
return 0;
}
这份代码中需要注意两点,一是:取反加一再与原值相与,做到只保留最右侧的1。二是:按位与的优先级竟然低于比较运算符。