目录
1.引言
交换两个数的值是比较基础也比较常用的算法,一般在交换两数的值是,最简单的方法适用的方法就是用中间变量暂存一个数。例如,要交换a,b的值,可使用中间变量c暂存其中的一个数。
上面的算法最大的缺点就是需要借助一个临时变量。那么不借助临时变量可以实现交换吗?答案是肯定的!这里我们可以用3种算法来实现:1)算术运算;2)位运算;3)栈实现。下面就具体来讲一下几种算法。
2.算术运算
2.1.加减法运算
核心代码如下:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a=12,b=882;
a = a + b; //【1】
b = a - b; //【2】
a = a - b; //【3】
printf("a=%d b=%d",a,b);
}
这种算法先将a和b的值赋给a,之后b等于a-b,这是b的值就变成了原来的a,最后a=a-b,a的值变为原来的b。
这种方法适用于整形和浮点型的数,但是用于浮点型时可能在减法后,数据可能会出现精度损失。
2.2.乘除法运算
核心代码如下:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a=1,b=2;
a = a * b; //【1】
b = a / b; //【2】
a = a / b; //【3】
printf("a=%d b=%d",a,b);
}
这个方法的基本思想和上一种加法很像,只是这个算法在b=0时出错,因为分子不能等于0。
3.3.取地址加减法运算
示例如下:
#include <iostream>
int main() {
int a = 2423;
int b = 444;
std::cout << "Before swap:" << std::endl;
std::cout << "a = " << a << ", b = " << b << std::endl;
// 使用指针来访问变量的地址
int* ptrA = &a;
int* ptrB = &b;
// 通过地址进行交换
*ptrA = *ptrA + *ptrB; // a now contains the sum of a and b
*ptrB = *ptrA - *ptrB; // b now contains the original value of a
*ptrA = *ptrA - *ptrB; // a now contains the original value of b
std::cout << "After swap:" << std::endl;
std::cout << "a = " << a << ", b = " << b << std::endl;
return 0;
}
3.位运算
^ : 异或运算,转成2进制,再相加
1^1 = 0;
1^0 = 1;
0^1 = 1;
0^0 = 0;
核心算法:
a ^= b;//a=a^b
b ^= a;//b=b^(a^b)=b^a^b=b^b^a=0^a=a
a ^= b;//a=(a^b)^a=a^b^a=a^a^b=0^b=b
此算法能够实现是由异或运算的特点决定的,通过异或运算能够使数据中的某些位翻转,其他位不变。这就意味着任意一个数与任意一个给定的值连续异或两次,值不变。
示例如下:
#include <iostream>
int main() {
int a = 1330;
int b = 240;
std::cout << "Before swap:" << std::endl;
std::cout << "a = " << a << ", b = " << b << std::endl;
a = a ^ b;
b = a ^ b;
a = a ^ b;
std::cout << "After swap:" << std::endl;
std::cout << "a = " << a << ", b = " << b << std::endl;
return 0;
}
1) 在算术运算符方法中,需要注意数值溢出的问题。如果a和b的值非常大,相加后可能会导致整数溢出,从而导致交换后的值不正确。
2) 位运算符方法则不会有这个问题,因为它只对二进制位进行操作,不会产生溢出。
3) 在实际编程中,如果对变量的值范围有明确的了解,并且确信不会导致溢出,可以使用算术运算符进行交换。否则,使用位运算符更为安全。
4.栈实现(后进先出)
核心代码如下:
int exchange(int x,int y)
{
stack S;
push(S,x);
push(S,y);
x=pop(S);
y=pop(S);
}
通过示例,我们可以看到如何在C++中不使用中间变量来交换两个变量的值。这种方法不仅可以提高代码的效率,还可以帮助我们更深入地理解C++的内存模型和指针操作。在实际编程中,我们需要根据具体情况进行选择,确保代码的正确性和可维护性。
延伸知识:std::exchange