找回密码
 立即注册

QQ登录

只需一步,快速开始

帖子
查看: 21454|回复: 80
收起左侧

不用中间数交换两个变量的方法

  [复制链接]
ID:282850 发表于 2019-11-26 10:49 | 显示全部楼层 |阅读模式
本帖最后由 f556 于 2019-11-26 10:50 编辑

再次翻看多年前的日志,看到自己记录的算法,联想到前些天论坛有人问了一个简单的问题:“怎么交换两组数?”
当时有人回答用中间变量,这是一种常用的方法。这个思路好比以下例子:一杯果汁A、一碗牛奶B,现在要互换一下容器,即把A换到碗里,B换到杯里。只有借助第3个容器C。操作是A--->C,B---->A,C----->B,这样才能完成交换。
有人回答用加减法,思路不错:
a=3;b=5;
a=a+b;         
b=a-b;
a=a-b;
但当时我提出有溢出问题,如235+122怎么办,设定a、b均为unsigned char;如果均为unsigned int同样有问题,不能用程序来限定a、b值的范围,特别是ADC的值。

我日志记录的不用中间数交换两个变量的方法,均利用C语言的异或运算。
异或逻辑:对应的位相比较,同=0,异=1,实际上可以理解就“按位求异”,即“异为真,同为假”
举例:
xxxx 1001  ^   0000 1111 = xxxx 0110(后4位翻转)
xxx1 xxxx  ^      1 0000 =xxx0 xxxx   
xxx0 xxxx  ^      1 0000 =xxx1 xxxx  

程序如下:
unsigned int aa=3456,bb=7890;
void main( void )
{
  aa=aa^bb;
  bb=bb^aa;
  aa=aa^bb;
}
运行结果见图片。

还未运行

还未运行

运行完

运行完

评分

参与人数 4黑币 +66 收起 理由
6789364 + 6 绝世好帖!
lenvov + 5 很给力!
八月初 + 5 厉害,佩服你的思路
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

举报

ID:645890 发表于 2019-11-28 08:36 | 显示全部楼层
夭寿,答案确实如此为何脑子还是转不太过来。
回复

举报

ID:190832 发表于 2019-11-30 12:33 | 显示全部楼层
这个太厉害了,精彩
回复

举报

ID:654169 发表于 2019-12-2 12:35 | 显示全部楼层
好厉害,电赛初学者刚好
回复

举报

ID:656472 发表于 2019-12-5 09:22 | 显示全部楼层
没看懂啊!!!
回复

举报

ID:540262 发表于 2019-12-10 09:49 来自触屏版 | 显示全部楼层
神仙算法
回复

举报

ID:282850 发表于 2019-12-10 17:07 | 显示全部楼层
解释一下,试算:
a=2   ----b 10
b=3   ----b 11             以下用二进制
a=a^b=10^11=01     这个数相当于一个中间值,不是原a,也不是原b
b=b^a=11^01=10  ---->2     使用了中间值01 (a)
a=a^b=01^10=11  ----->3     使用了中间值01 ,也使用了交换好的b

异或象加法一样,不分先后顺序
改程序如下图,也可
sss.jpg
回复

举报

ID:663421 发表于 2019-12-13 17:59 | 显示全部楼层
牛逼,学习了
回复

举报

ID:653902 发表于 2019-12-16 08:51 | 显示全部楼层
这种交换方法有一个前提,就是aa和bb不能相等,如果相等,则会得出错误的结果。所以在做异或运算前,需要进行判断。
回复

举报

ID:282850 发表于 2019-12-17 14:13 | 显示全部楼层
rotga 发表于 2019-12-16 08:51
这种交换方法有一个前提,就是aa和bb不能相等,如果相等,则会得出错误的结果。所以在做异或运算前,需要进 ...

真的吗?纯属你的主观意断!
回复

举报

ID:282850 发表于 2019-12-17 14:18 | 显示全部楼层
否定楼上的想当然,两个相同数的交换。见运行图片
人算:
a=1;  b=1;
a=a^b=0;
b=a^b=0^1=1;
a=a^b=0^1=1;
错在哪里!
ssss.jpg
回复

举报

ID:351097 发表于 2019-12-20 15:56 | 显示全部楼层
你这种方法虽然可行,涉及到异或处理,编译出的汇编代码会比中间变量法多一些,这样的话,单片机就需要花更多是时间去处理,可以说效率低。而且这样写,代码的可读性非常差。
回复

举报

ID:669731 发表于 2019-12-21 12:37 | 显示全部楼层
多学一种思路,至少以后看的懂 谢谢楼主的讲解 楼主说的两种我看过,这个没看过
回复

举报

ID:653902 发表于 2019-12-22 22:26 | 显示全部楼层
如果只是在main中这样做,结果没有问题,但是在实际编程中,以调用函数的方式,那么只能用指针传递实参,如果两个数值相等的话,这样就会出错。你可以试一试。
回复

举报

ID:653902 发表于 2019-12-22 22:54 | 显示全部楼层
#include <stdio.h>
void swap(int *a,int *b)
{
        *a^=*b;
        *b^=*a;
        *a^=*b;

}
void main(void)
{
        int test[2] = {21,23};
        swap(&test[0],&test[0]);
        printf("test[0]=%d test[1]=%d",test[0],test[1]);
}
运行结果:test[0]=0 test[1]=23
回复

举报

ID:673561 发表于 2019-12-25 15:29 | 显示全部楼层
学到了,很有帮助,这个平台很不错
回复

举报

ID:282850 发表于 2019-12-27 16:31 | 显示全部楼层
rotga 发表于 2019-12-22 22:54
#include
void swap(int *a,int *b)
{

你程序有一句明显错误。
回复

举报

ID:664974 发表于 2019-12-27 22:18 来自触屏版 | 显示全部楼层
太麻烦了
回复

举报

ID:282850 发表于 2019-12-28 12:36 | 显示全部楼层
rotga 发表于 2019-12-22 22:54
#include
void swap(int *a,int *b)
{

有一个语句明显错了,请改正。
另外,我个人非常厌恶printf,这个纯无用的垃圾语句。从你用printf可以看出受了唐大师的毒害,还是重新找本书或者混一下网站、论坛。
回复

举报

ID:653902 发表于 2019-12-31 10:08 | 显示全部楼层
不是明显错了,而是模拟在复杂环境里面,很有可能产生待比较的两个数的指针指向同一地址,而结果你也看到了,是否和你之前想象的结果一致?你的心态很浮躁,我的水平是不高,但三人行必有我师焉。是否你认为给你指出潜在的错误逻辑只能是水平比你高的人才有资格?这个帖子我无意和你扯这些口舌之争。如果技术上还有需讨论的地方,欢迎发表观点。关于用异或交换数字,是个思路,但第一,对于直接交换,如果操作对象是同一个数,会有错误结果。第二,运行效率低,代码可读性差。这个早已是定论。

评分

参与人数 1黑币 +5 收起 理由
zpmpok001 + 5

查看全部评分

回复

举报

ID:676429 发表于 2019-12-31 10:33 | 显示全部楼层
好厉害,初学者刚好
回复

举报

ID:328200 发表于 2020-1-11 12:11 | 显示全部楼层
#include <stdio.h>
void swap(int *a,int *b)
{
        *a^=*b;
        *b^=*a;
        *a^=*b;

}
void main(void)
{
        int test[2] = {21,21};
        swap(&test[0],&test[1]);
        printf("test[0]=%d test[1]=%d",test[0],test[1]);
}
运行结果:
test[0]=21 test[1]=21Press any key to continue
回复

举报

ID:392682 发表于 2020-1-17 11:05 | 显示全部楼层
感谢,涨知识了
回复

举报

ID:348676 发表于 2020-1-20 16:11 | 显示全部楼层
学习了,很有帮助
回复

举报

ID:348676 发表于 2020-1-20 16:30 | 显示全部楼层
rotga 发表于 2019-12-16 08:51
这种交换方法有一个前提,就是aa和bb不能相等,如果相等,则会得出错误的结果。所以在做异或运算前,需要进 ...

相等就不用交换了
回复

举报

ID:497328 发表于 2020-2-2 20:11 | 显示全部楼层
这么好的贴子不顶不行
回复

举报

ID:689598 发表于 2020-2-3 01:00 | 显示全部楼层
不具通用性,只能在特殊场景里使用
回复

举报

ID:692149 发表于 2020-2-15 13:18 | 显示全部楼层
这个方法好,学习了
回复

举报

ID:575679 发表于 2020-2-15 15:07 | 显示全部楼层
谢谢大佬 学习了
回复

举报

ID:507431 发表于 2020-2-20 13:32 | 显示全部楼层
有意思
回复

举报

ID:702102 发表于 2020-3-11 07:45 | 显示全部楼层
过来学习!
回复

举报

ID:695749 发表于 2020-3-15 19:59 | 显示全部楼层
先学习这个方法,在实践中运用,感谢大家的分享!
回复

举报

ID:284107 发表于 2020-3-15 21:19 来自触屏版 | 显示全部楼层
两次对同一个数异或还等于自己
回复

举报

ID:234355 发表于 2020-3-22 13:53 | 显示全部楼层
int x,y;
x=x+y;
y=x-y;
x=x-y;
回复

举报

ID:265584 发表于 2020-4-12 11:04 | 显示全部楼层
学习学习,感谢!
回复

举报

ID:311846 发表于 2020-4-21 13:54 | 显示全部楼层
rotga 发表于 2019-12-16 08:51
这种交换方法有一个前提,就是aa和bb不能相等,如果相等,则会得出错误的结果。所以在做异或运算前,需要进 ...

你的基础不行啊,楼主这么详细的说明了你都还没明白么?
回复

举报

ID:311846 发表于 2020-4-21 13:57 | 显示全部楼层
wanghz12 发表于 2020-3-22 13:53
int x,y;
x=x+y;
y=x-y;

这个的前提是相加不能超出int范围
回复

举报

ID:716413 发表于 2020-4-22 20:26 | 显示全部楼层
天才算法!
回复

举报

ID:741805 发表于 2020-4-30 16:52 | 显示全部楼层
把加法换为减法不就可以了?减法不会溢出,也比异或效率高
回复

举报

ID:741805 发表于 2020-4-30 16:54 | 显示全部楼层
a=3;b=5;
a=a-b;
b=a+b;
a=b-a;
回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表