找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 21166|回復: 80
打印 上一主題 下一主題
收起左側

不用中間數交換兩個變量的方法

  [復制鏈接]
跳轉到指定樓層
樓主
ID:282850 發(fā)表于 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;
}
運行結果見圖片。

stest.jpg (102.67 KB, 下載次數: 291)

還未運行

還未運行

stest2.jpg (62.3 KB, 下載次數: 314)

運行完

運行完

評分

參與人數 4黑幣 +66 收起 理由
6789364 + 6 絕世好帖!
lenvov + 5 很給力!
八月初 + 5 厲害,佩服你的思路
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏20 分享淘帖 頂10 踩
回復

使用道具 舉報

沙發(fā)
ID:645890 發(fā)表于 2019-11-28 08:36 | 只看該作者
夭壽,答案確實如此為何腦子還是轉不太過來。
回復

使用道具 舉報

板凳
ID:190832 發(fā)表于 2019-11-30 12:33 | 只看該作者
這個太厲害了,精彩
回復

使用道具 舉報

地板
ID:654169 發(fā)表于 2019-12-2 12:35 | 只看該作者
好厲害,電賽初學者剛好
回復

使用道具 舉報

5#
ID:656472 發(fā)表于 2019-12-5 09:22 | 只看該作者
沒看懂啊。。
回復

使用道具 舉報

6#
ID:540262 發(fā)表于 2019-12-10 09:49 來自手機 | 只看該作者
神仙算法
回復

使用道具 舉報

7#
ID:282850 發(fā)表于 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 (21.03 KB, 下載次數: 271)

sss.jpg
回復

使用道具 舉報

8#
ID:663421 發(fā)表于 2019-12-13 17:59 | 只看該作者
牛逼,學習了
回復

使用道具 舉報

9#
ID:653902 發(fā)表于 2019-12-16 08:51 | 只看該作者
這種交換方法有一個前提,就是aa和bb不能相等,如果相等,則會得出錯誤的結果。所以在做異或運算前,需要進行判斷。
回復

使用道具 舉報

10#
ID:282850 發(fā)表于 2019-12-17 14:13 | 只看該作者
rotga 發(fā)表于 2019-12-16 08:51
這種交換方法有一個前提,就是aa和bb不能相等,如果相等,則會得出錯誤的結果。所以在做異或運算前,需要進 ...

真的嗎?純屬你的主觀意斷!
回復

使用道具 舉報

11#
ID:282850 發(fā)表于 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 (52.97 KB, 下載次數: 225)

ssss.jpg
回復

使用道具 舉報

12#
ID:351097 發(fā)表于 2019-12-20 15:56 | 只看該作者
你這種方法雖然可行,涉及到異或處理,編譯出的匯編代碼會比中間變量法多一些,這樣的話,單片機就需要花更多是時間去處理,可以說效率低。而且這樣寫,代碼的可讀性非常差。
回復

使用道具 舉報

13#
ID:669731 發(fā)表于 2019-12-21 12:37 | 只看該作者
多學一種思路,至少以后看的懂 謝謝樓主的講解 樓主說的兩種我看過,這個沒看過
回復

使用道具 舉報

14#
ID:653902 發(fā)表于 2019-12-22 22:26 | 只看該作者
如果只是在main中這樣做,結果沒有問題,但是在實際編程中,以調用函數的方式,那么只能用指針傳遞實參,如果兩個數值相等的話,這樣就會出錯。你可以試一試。
回復

使用道具 舉報

15#
ID:653902 發(fā)表于 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
回復

使用道具 舉報

16#
ID:673561 發(fā)表于 2019-12-25 15:29 | 只看該作者
學到了,很有幫助,這個平臺很不錯
回復

使用道具 舉報

17#
ID:282850 發(fā)表于 2019-12-27 16:31 | 只看該作者
rotga 發(fā)表于 2019-12-22 22:54
#include
void swap(int *a,int *b)
{

你程序有一句明顯錯誤。
回復

使用道具 舉報

18#
ID:664974 發(fā)表于 2019-12-27 22:18 來自手機 | 只看該作者
太麻煩了
回復

使用道具 舉報

19#
ID:282850 發(fā)表于 2019-12-28 12:36 | 只看該作者
rotga 發(fā)表于 2019-12-22 22:54
#include
void swap(int *a,int *b)
{

有一個語句明顯錯了,請改正。
另外,我個人非常厭惡printf,這個純無用的垃圾語句。從你用printf可以看出受了唐大師的毒害,還是重新找本書或者混一下網站、論壇。
回復

使用道具 舉報

20#
ID:653902 發(fā)表于 2019-12-31 10:08 | 只看該作者
不是明顯錯了,而是模擬在復雜環(huán)境里面,很有可能產生待比較的兩個數的指針指向同一地址,而結果你也看到了,是否和你之前想象的結果一致?你的心態(tài)很浮躁,我的水平是不高,但三人行必有我?guī)熝伞J欠衲阏J為給你指出潛在的錯誤邏輯只能是水平比你高的人才有資格?這個帖子我無意和你扯這些口舌之爭。如果技術上還有需討論的地方,歡迎發(fā)表觀點。關于用異或交換數字,是個思路,但第一,對于直接交換,如果操作對象是同一個數,會有錯誤結果。第二,運行效率低,代碼可讀性差。這個早已是定論。

評分

參與人數 1黑幣 +5 收起 理由
zpmpok001 + 5

查看全部評分

回復

使用道具 舉報

21#
ID:676429 發(fā)表于 2019-12-31 10:33 | 只看該作者
好厲害,初學者剛好
回復

使用道具 舉報

22#
ID:328200 發(fā)表于 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
回復

使用道具 舉報

23#
ID:392682 發(fā)表于 2020-1-17 11:05 | 只看該作者
感謝,漲知識了
回復

使用道具 舉報

24#
ID:348676 發(fā)表于 2020-1-20 16:11 | 只看該作者
學習了,很有幫助
回復

使用道具 舉報

25#
ID:348676 發(fā)表于 2020-1-20 16:30 | 只看該作者
rotga 發(fā)表于 2019-12-16 08:51
這種交換方法有一個前提,就是aa和bb不能相等,如果相等,則會得出錯誤的結果。所以在做異或運算前,需要進 ...

相等就不用交換了
回復

使用道具 舉報

26#
ID:497328 發(fā)表于 2020-2-2 20:11 | 只看該作者
這么好的貼子不頂不行
回復

使用道具 舉報

27#
ID:689598 發(fā)表于 2020-2-3 01:00 | 只看該作者
不具通用性,只能在特殊場景里使用
回復

使用道具 舉報

28#
ID:692149 發(fā)表于 2020-2-15 13:18 | 只看該作者
這個方法好,學習了
回復

使用道具 舉報

29#
ID:575679 發(fā)表于 2020-2-15 15:07 | 只看該作者
謝謝大佬 學習了
回復

使用道具 舉報

30#
ID:507431 發(fā)表于 2020-2-20 13:32 | 只看該作者
有意思
回復

使用道具 舉報

31#
ID:702102 發(fā)表于 2020-3-11 07:45 | 只看該作者
過來學習!
回復

使用道具 舉報

32#
ID:695749 發(fā)表于 2020-3-15 19:59 | 只看該作者
先學習這個方法,在實踐中運用,感謝大家的分享!
回復

使用道具 舉報

33#
ID:284107 發(fā)表于 2020-3-15 21:19 來自手機 | 只看該作者
兩次對同一個數異或還等于自己
回復

使用道具 舉報

34#
ID:234355 發(fā)表于 2020-3-22 13:53 | 只看該作者
int x,y;
x=x+y;
y=x-y;
x=x-y;
回復

使用道具 舉報

35#
ID:265584 發(fā)表于 2020-4-12 11:04 | 只看該作者
學習學習,感謝!
回復

使用道具 舉報

36#
ID:311846 發(fā)表于 2020-4-21 13:54 | 只看該作者
rotga 發(fā)表于 2019-12-16 08:51
這種交換方法有一個前提,就是aa和bb不能相等,如果相等,則會得出錯誤的結果。所以在做異或運算前,需要進 ...

你的基礎不行啊,樓主這么詳細的說明了你都還沒明白么?
回復

使用道具 舉報

37#
ID:311846 發(fā)表于 2020-4-21 13:57 | 只看該作者

這個的前提是相加不能超出int范圍
回復

使用道具 舉報

38#
ID:716413 發(fā)表于 2020-4-22 20:26 | 只看該作者
天才算法!
回復

使用道具 舉報

39#
ID:741805 發(fā)表于 2020-4-30 16:52 | 只看該作者
把加法換為減法不就可以了?減法不會溢出,也比異或效率高
回復

使用道具 舉報

40#
ID:741805 發(fā)表于 2020-4-30 16:54 | 只看該作者
a=3;b=5;
a=a-b;
b=a+b;
a=b-a;
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表