main()
{
int x,y,temp;
scanf(“%d%d”,&x,&y);
printf(“x=%d,y=%d\n”,x,y);
temp=x;
x=y;
y=temp;
printf(“x=%d,y=%d\n”,x,y);
}
写出不用第三变量交换x和y值的算法
用算术或异或
x = x + y;
y = x - y;
x = x - y;
或
x = x^y;// 只能对int,char..
y = x^y;
x = x^y;
或
x ^= y ^= x;
2) 指针操作
对指针的操作实际上进行的是整数运算。比如:两个int指针相减得到一个整数N,该整数表示两个指针变量在内存中的储存位置隔了N*sizeof(int)个字节;int指针和一个整数相加,例如“a+10”表示以a为基地址,偏移为10*sizeof(int)处的int变量。所以我们完全可以通过和算术算法类似的运算来完成指针变量值的交换,从而达到交换变量的目的。即:
int *a,*b;
a=new int(10); //给指针赋值
b=new int(20); //a=0x00030828,b=0x00030840
a=(int*)(b-a); //a=0x00000006
b=(int*)(b-int(a)); //b=0x00030828
a=(int*)(b+int(a)); //a=0x00030840
需要注意的是:最后三句话中,只有第一句是两个指针之间的计算,其他都是指针和整数的计算,否则会导致计算错误,严重导致系统出错。
通过以上运算a、b的地址就完成了交换,a指向了原先b指向的值,b指向原先a指向的值!
此算法同样没有使用第三变量就完成了值的交换,与算术算法比较它显得不好理解,但是它有它的优点即在交换很大的数据类型时,比如说自定义的大型结构或者类,它的执行速度比算术算法快。因为它交换的时地址,而变量值在内存中是没有移动过的。(以下称为地址算法)
用异或交换两个整数的陷阱
前面我们谈到了,可用通过异或运算交换两个数,而不需要任何的中间变量。 如下面:
void exchange(int &a, int &b)
{
a ^= b;
b ^= a;
a ^= b;
}
然而,这里面却存在着一个非常隐蔽的陷阱。
通常我们在对数组进行操作的时候,会交换数组中的两个元素,如exchang(&a[i], &b[j]), 这儿如果i==j了(这种情况是很可能发生的),得到的结果就并非我们所期望的。
void main()
{
int a[2] = {1, 2};
exchange(a[0], a[1]); //交换a[0]和a[1]的值
printf("1---a[0]=%d a[1]=%d\n", a[0], a[1]);
exchange(a[0], a[0]); //将a[0]与自己进行交换
printf("2---a[0]=%d a[1]=%d\n", a[0], a[1]);
}
上面那段测试代码的输出是:
1---a[0]=2 a[1]=1
2---a[0]=0 a[1]=1
很意外吧,第一次的交换正确的执行了,但是第二次调用exchange的时候却将a[0]置为了0. 仔细分析,不难发现,这正是我们在exchange里面用异或实现交换所造成的。如果输入a和b是同一个数,exchange里面代码相当于:
a ^= a;
a ^= a;
a ^= a;
成了a做了3次于自己的异或,其结果当然是0了。
既然这样,我们就不能够在任何使用交换的地方采用异或了,即使要用,也一定要在交换之前判断两个数是否已经相等了,如下:
void exchange(int &a, int &b)
{
if(a == b) return; //防止&a,&b指向同一个地址;那样结果会错误。
a ^= b;
b ^= a;
a ^= b;
}