编程中肯定会常常用到swap这个函数,他的意思就是交换两个变量的数值,但是这个过程显然可以很容易通过手动过程实现,总结了一下,大致有5种实现。
主函数:
main()
{ int a,b;
a=10; b=30;
swap(&a,&b);
printf("%d %d/n",a,b);
}
方法一:
通过临时变量实现,也是最常见的方法:
void swap(int a ,int b)
{int t;
t=a;
a=b;
b=t;
}
t是核心内容,作为临时变量进行交换。这种算法易于理解,但需要一个临时变量。
方法二:
算术运算,就是通过普通的+和-运算来实现:
void swap(int a ,int b)
{
a=b-a; //a=20;b=30
b=b-a; //a=20;b=10
a=b+a; //a=30;b=10
}
证 明:把a、b看做数轴上的点,围绕两点间的距离来进行计算。第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;第二句“b=b-a”求出a到 原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a=b+a”求出b到原点的距离(a到原点距离与ab两点距离之和),并 且将其保存在a中。完成交换。
此算法与方法一相比,多了三个计算的过程,但是没有借助临时变量。
方法三:
指针地址操作, 因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“a+ 10”表示以a为基地址的在a后10个a类数据单元的地址,所以理论上可以通过和算术算法类似的运算来完成地址的交换,从而达到交换变量的目的:
void swap(int a ,int b)
{
if(a<b)
{
a=(int*)(b-a);
b=(int*)(b-(int(a)&0x0000ffff));
a=(int*)(b+(int(a)&0x0000ffff));
}
else
{
b=(int*)(a-b);
a=(int*)(a-(int(b)&0x0000ffff));
b=(int*)(a+(int(b)&0x0000ffff));
}
这 里采用位运算中的与运算“int(a)&0x0000ffff”,因为地址中高16位为段地址,后16位为位移地址,将它和0x0000ffff 进行与运算后,段地址被屏蔽,只保留位移地址。这样可以避免由系统自动采用补码的形式表示负的位移所产生的错误,需要说明一下就是一般我们写的 0x00000100h之类的地址并不是其变量所在的真实地址,而是要加上变量所在内存区的基地址,例如前面的变量的实际地址可能是 0x008f0100h,其中0x008f即为基地址.它是由编译器自动添加的。
此算法同样没有使用第三变量就完成了值的交换,与算术算法比较它显得不好理解,但是它有它的优点即在交换很大的数据类型时,它的执行速度比算法一快。因为它交换的时地址,而变量值在内存中是没有移动过的。
方法四:
通过异或运算也能实现变量的交换,这也许是最为神奇的:
void swap(int a ,int b)
{
a=a^b;
b=a^b;
a=a^b;
}
证明:a1=a0^b0; b1=b0^a1=b0^(a0^b0)=a0^b0^b0=a0; a2=a1^b1=(a0^b0)^a0=b0^a0^a0=b0;
此算法能够实现是由异或运算的特点决定的,通过异或运算能够使数据中的某些位翻转,其他位不变。这就意味着任意一个数与任意一个给定的值连续异或两次,值不变。
方法五:
堆栈实现,很普通的栈操作就行,写法很多,这里通过asm实现:
void swap(int a ,int b)
{
__asm{
push a;
push b;
pop a;
pop b;
}
}
这种方法可能在值大的情况下会有溢出的情况,所以不推荐。
另外还会出现一些技巧性的操作来实现,但还是应用以上的方法,只是形式有些变动,例如使用逗号表达式:a=(a = a+b, b = a-b, a-b);
这几种方法理论上方法三的速度最快,但其实如果对这几种方法反汇编所得到的都是20多行汇编代码,所以没必要过分追究那种最快,这里进行罗列就是给大家一个选择的机会。
文章为原创,转载欢迎,但请注明出处。
主函数:
main()
{ int a,b;
a=10; b=30;
swap(&a,&b);
printf("%d %d/n",a,b);
}
方法一:
通过临时变量实现,也是最常见的方法:
void swap(int a ,int b)
{int t;
t=a;
a=b;
b=t;
}
t是核心内容,作为临时变量进行交换。这种算法易于理解,但需要一个临时变量。
方法二:
算术运算,就是通过普通的+和-运算来实现:
void swap(int a ,int b)
{
a=b-a; //a=20;b=30
b=b-a; //a=20;b=10
a=b+a; //a=30;b=10
}
证 明:把a、b看做数轴上的点,围绕两点间的距离来进行计算。第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;第二句“b=b-a”求出a到 原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a=b+a”求出b到原点的距离(a到原点距离与ab两点距离之和),并 且将其保存在a中。完成交换。
此算法与方法一相比,多了三个计算的过程,但是没有借助临时变量。
方法三:
指针地址操作, 因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“a+ 10”表示以a为基地址的在a后10个a类数据单元的地址,所以理论上可以通过和算术算法类似的运算来完成地址的交换,从而达到交换变量的目的:
void swap(int a ,int b)
{
if(a<b)
{
a=(int*)(b-a);
b=(int*)(b-(int(a)&0x0000ffff));
a=(int*)(b+(int(a)&0x0000ffff));
}
else
{
b=(int*)(a-b);
a=(int*)(a-(int(b)&0x0000ffff));
b=(int*)(a+(int(b)&0x0000ffff));
}
这 里采用位运算中的与运算“int(a)&0x0000ffff”,因为地址中高16位为段地址,后16位为位移地址,将它和0x0000ffff 进行与运算后,段地址被屏蔽,只保留位移地址。这样可以避免由系统自动采用补码的形式表示负的位移所产生的错误,需要说明一下就是一般我们写的 0x00000100h之类的地址并不是其变量所在的真实地址,而是要加上变量所在内存区的基地址,例如前面的变量的实际地址可能是 0x008f0100h,其中0x008f即为基地址.它是由编译器自动添加的。
此算法同样没有使用第三变量就完成了值的交换,与算术算法比较它显得不好理解,但是它有它的优点即在交换很大的数据类型时,它的执行速度比算法一快。因为它交换的时地址,而变量值在内存中是没有移动过的。
方法四:
通过异或运算也能实现变量的交换,这也许是最为神奇的:
void swap(int a ,int b)
{
a=a^b;
b=a^b;
a=a^b;
}
证明:a1=a0^b0; b1=b0^a1=b0^(a0^b0)=a0^b0^b0=a0; a2=a1^b1=(a0^b0)^a0=b0^a0^a0=b0;
此算法能够实现是由异或运算的特点决定的,通过异或运算能够使数据中的某些位翻转,其他位不变。这就意味着任意一个数与任意一个给定的值连续异或两次,值不变。
方法五:
堆栈实现,很普通的栈操作就行,写法很多,这里通过asm实现:
void swap(int a ,int b)
{
__asm{
push a;
push b;
pop a;
pop b;
}
}
这种方法可能在值大的情况下会有溢出的情况,所以不推荐。
另外还会出现一些技巧性的操作来实现,但还是应用以上的方法,只是形式有些变动,例如使用逗号表达式:a=(a = a+b, b = a-b, a-b);
这几种方法理论上方法三的速度最快,但其实如果对这几种方法反汇编所得到的都是20多行汇编代码,所以没必要过分追究那种最快,这里进行罗列就是给大家一个选择的机会。
文章为原创,转载欢迎,但请注明出处。