青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

堅持學(xué)習(xí)/暴露問題/不斷提升

c++/設(shè)計模式/算法結(jié)構(gòu)/系統(tǒng)
posts - 2, comments - 20, trackbacks - 0, articles - 0

本篇摘要

  交換兩個變量是非常古老的話題了,然而本文絕對保證給你新鮮的感覺!本文涉及到最簡單的“不用臨時變量交換兩個整數(shù)”還涉及到如果利用異或來實現(xiàn)兩個指針、兩個浮點數(shù)的交換,要知道指針的浮點數(shù)是不允許直接異或運算的哦;同時本文還闡述了如何交換用戶自定義類型及其指針。

本文完全是個人自由發(fā)揮之作,歡迎廣大磚家來拍磚,我個人感覺文中必然有很多不足,甚至錯誤之處,這并非我謙虛,事實上我寫本文的目的就是希望在挨磚板中成長!新人或許看不懂很多東西,如果你看不懂,那么就不要隨便膜拜,因為看不懂的或許原本就是錯的,高手看完后如果本文寫得還可以,那么請留下好評,以供新手參考本文是否有閱讀本文的必要,如果覺得本文完全是垃圾,那么請不要客氣,您可以赤裸地,露骨地指出本文的錯誤和不足,讓本人在批評中進步,但請不要進行人身攻擊,謝謝!

準(zhǔn)備工作

  由于本文涉及到交換兩個用戶自定義類型的變量,為了舉例方便,本文定義如下的Person類(其中省略了拷貝構(gòu)造函數(shù)的重寫,因為本文不用到它):

class Person
{
public:
         Person(
int age ,const char* name ):m_Age(age)
         {
                   
int len = strlen(name);
                   
this->m_Name = new char[len+1];
                   strcpy(
this->m_Name,name);
         }
         Person()
         {
                   
this->m_Age = -1;
                   
this->m_Name = 0;
         }
         
void PrintSelf()
         {
                   cout
<<this->m_Name<<":"<<this->m_Age<<endl;
         }
         Person
& operator= (const Person& other)
         {
                   
if (this == &other)
                   {
                            
return *this;
                   }
                   
else
                   {
                            
this->m_Age = other.m_Age;
                            delete 
this->m_Name;
                            
int len = strlen(other.m_Name);
                            
this->m_Name = new char[len+1];
                            strcpy(
this->m_Name,other.m_Name);
                            
return *this;
                   }
         }
         
~Person()
         {
                   delete 
this->m_Name;
         }
private:
         
int m_Age;
         
char* m_Name;
};

  為了后文表述方便,這里再定義Person類的兩個對象和兩個指針,定義如下:

Person youngMan(18,” young man”);

Person oldMan(81,” old man”);

Person* pYoungMan = &youngMan;

Person* pOldMan = &oldMan;

最常見的交換兩個對象的方法:GeneralSwap

通常,我們?yōu)榱私粨Q兩個變量都采取下面的方法來實現(xiàn),它需要一個臨時變量:

template<class T>
void GeneralSwap(T& a,T& b)
{
         T temp;
         temp 
= a;
         a 
= b;
         b 
= temp;
}

    顯然人人都知道這個寫法,但是我仍然覺得有必要重點申明幾點:1、注意函數(shù)的參數(shù)是引用(也可指針),為什么我就不解釋了;2、這個交換函數(shù)基本上是最簡單、最通用的,簡單到人人都會寫,通用到它幾乎可適用于任何數(shù)據(jù)類型:char , int , long , float, double等各種系統(tǒng)自定義數(shù)學(xué)類型(無符號的,帶符號的),用戶自定義數(shù)據(jù)類型(需要有默認(rèn)構(gòu)造函數(shù),否則語句T temp;會報錯),以及各種指針(系統(tǒng)自定義類型的指針,和用戶自定義類型的指針)。當(dāng)然用戶自定義類型中如果包含了指針數(shù)據(jù)成員,那么需要重載賦值運算符,事實上這樣的用戶自定義類,你都應(yīng)該自己重寫賦值運算符、拷貝構(gòu)造函數(shù),否則不但不能使用GeneralSwap,其他涉及到拷貝和賦值的操作都可能導(dǎo)致出錯!

利用GeneralSwap交換兩個用戶自定義對象

    下面深入探討一下關(guān)于用戶自定義對象的交換問題:針對準(zhǔn)備工作中的Person類的兩個對象youngMan和oldMan語句GeneralSwap(youngMan,oldMan);能實現(xiàn)他們的交換。短短一行代碼就能實現(xiàn)將一個18歲的花季少男跟一個81歲的老頭子掉包,這像不像是耍魔術(shù)啊,呵呵。要注意了,該交換代碼雖短,但涉及到默認(rèn)構(gòu)造函數(shù)的調(diào)用(GeneralSwap中的T temp;語句)和賦值運算符重載函數(shù)的調(diào)用(GeneralSwap中的三個賦值語句)。

或許您很少這么用吧,事實上在我寫本文之前,我都沒真正交換過兩個自定義的對象,通常我們都不愿意這么交換兩個自定義對象。原因是效率太低!或許你要問,萬一有的應(yīng)用就是需要交換兩個自定義的對象怎么辦?好辦,用指針啊!對,指針的好處就是效率高,為什么C++比java效率高,原因之一就是java取消了指針。下面的第一行代碼就是交換兩個Person類的指針:

GeneralSwap(pYoungMan,pOldMan);

//GeneralSwap(*pYoungMan,* pOldMan);     //效率低

    為什么使用指針就效率高了呢?原因是指針就是地址,地址就是整數(shù),于是問題等價于交換兩個整數(shù),因此它不調(diào)用賦值運算符重載函數(shù)!只要你在應(yīng)用程序中始終通過指向?qū)ο蟮闹羔榿碓L問對象,那么交換兩個指針就能達(dá)到交換對象的目的。注意被注釋掉的第二行代碼,它是正確的,但是它又回到了交換兩個實際對象,其效率低,最好不要這么用!

對于這個最常見、最簡單的GeneralSwap我都廢話了一大堆,而且還扯出了一個沒多少用的關(guān)于用戶自定義對象的交換問題,這實屬個人思維散射,請磚家們狠狠地拍。

在進行下一個方法之前,再次強調(diào)一點,這個方法的特點是簡單、通用!后面的方法都將與之做比較。

利用加減法實現(xiàn)兩個數(shù)的交換

    幾乎人人都知道還可以利用加減法來實現(xiàn)兩個數(shù)的交換,其代碼也異常簡單:

template<class T>
void Add_Sub_Swap_1(T& a, T& b)
{
        a 
= a+b;
        b 
= a-b;
         a 
= a-b;
}

    Add_Sub_Swap_1可以用于交換兩個整數(shù),但由于涉及加減法,因此有數(shù)據(jù)溢出的危險;也可以用于交換浮點數(shù),但是有可能由于舍入誤差導(dǎo)致結(jié)果不準(zhǔn)確。

Add_Sub_Swap_1不能用于交換兩個用戶自定義的對象,下面的語句編譯就通過不,編譯器告訴你Person類沒有定義operator +等符號:

Add_Sub_Swap_1(youngMan,oldMan);//編譯通不過!

    Add_Sub_Swap_1不能用于交換兩個指針,語句Add_Sub_Swap_1(pYoungMan,pOldMan);編譯時將報錯:error C2110: cannot add two pointers,是的,兩個指針不能直接做加法運算(減法是可以的)。那么是不是就不能利用加減法實現(xiàn)兩個指針的交換呢?答案是:“可以!”,接下來我將闡述如何實現(xiàn)。

利用加減法交換兩個指針

    Add_Sub_Swap_1不能用于交換兩個指針,前面我說可以用加減法來實現(xiàn)兩個指針的交換,這是有根據(jù)的:指針仍然是變量,只不過它是存儲普通變量的地址的變量。只要我們把指針“看作”變量,那么就能實現(xiàn)加法。那么如何把指針“看作”變量呢?答案是:“通過強制類型轉(zhuǎn)換”!指針表示變量的地址,在32位平臺上它是一個無符號的整數(shù),因此可以將指針強制轉(zhuǎn)換為無符號類型的整數(shù)。我對上面的Add_Sub_Swap_1進行了改進:

template<class T>
void Add_Sub_Swap_2(T& a, T& b)
{
         
*(( unsigned*)(&a)) = *(( unsigned*)(&a)) + *(( unsigned*)(&b));
         
*(( unsigned*)(&b)) = *(( unsigned*)(&a)) - *(( unsigned*)(&b));
         
*(( unsigned*)(&a)) = *(( unsigned*)(&a)) - *(( unsigned*)(&b));
}

    利用Add_Sub_Swap_2既可以交換兩個普通的整數(shù)、浮點數(shù)同時它可以交換兩個任意類型的指針(包含系統(tǒng)預(yù)定義類型和用戶自定義類型的指針,其實本質(zhì)上所有指針都屬于同一種類型:32位無符號整數(shù)類型)。不信您試試Add_Sub_Swap_2(pYoungMan,pOldMan);它能得到正確答案。

雖然Add_Sub_Swap_2解決了Add_Sub_Swap_1無法交換兩個指針的問題,但是它仍然無法交換兩個用戶自定義類型的變量,原因是用戶自定義類型沒有加減法運算。看來要想用加減法實現(xiàn)兩個用戶定義類型的交換是不可能的了(除非用戶自定義的operator+和operator-能滿足交換兩個對象的目的,這很難,除非是非常簡單的用戶自定義類型,比如你不使用系統(tǒng)類型int非要定義一個MyInt類)。

利用異或?qū)崿F(xiàn)兩個整數(shù)的交換

    同樣地,幾乎人人都知道利用異或來交換兩個數(shù),其實現(xiàn)也非常簡單:

template <class T>
void Xor_Swap_1(T& a,T& b)
{
         a 
= a^b;
         b 
= a^b;
         a 
= a^b;
}

    上面的函數(shù)的實用性非常有限,它只能交換兩個整數(shù)(包含char,int,long),要想交換兩個浮點數(shù)是不行的,因為浮點數(shù)不能參與位運算,要想交換兩個指針也是不行的,編譯器不允許你把兩個指針拿來做位運算,要想交換兩個用戶自定義對象也是不行的,因為它仍然不能參與位運算。那么是不是利用異或交換兩個變量就沒法用于浮點數(shù)、指針和用戶自定義的對象了呢?答案是“能”!后面幾節(jié)我將闡述這些問題。

利用異或?qū)崿F(xiàn)兩個float和指針的交換

    前面的Xor_Swap_1無法實現(xiàn)兩個浮點數(shù)和指針的交換,其原因是浮點數(shù)和指針均不直接支持位運算。那么如何才能利用異或來交換兩個浮點數(shù)和指針呢?方法仍然是“強制類型轉(zhuǎn)換”!因為浮點數(shù)在內(nèi)存中仍然是用一串二進制bit來表示的嘛,只要把浮點數(shù)看作(強制類型轉(zhuǎn)換)二進制bit構(gòu)成的整數(shù),那么就能進行位運算了,至于指針嘛,處理方法完全相同。具體如何做呢,其實現(xiàn)大概是這樣的:

template <class T>
void Xor_Swap_2(T& a,T& b)
{
         
*((unsigned*)(&a)) = *((unsigned*)(&a)) ^ *((unsigned*)(&b));
         
*((unsigned*)(&b)) = *((unsigned*)(&a)) ^ *((unsigned*)(&b));
         
*((unsigned*)(&a)) = *((unsigned*)(&a)) ^ *((unsigned*)(&b));
}

    利用這個函數(shù)可以交換兩個float類型的變量,也可以交換任意類型的指針!非常值得注意的是:用它交換兩個double類型數(shù)據(jù)或者兩個Person類的對象(youngMan,oldMan)均能編譯通過,但是其結(jié)果卻是錯的。至于為什么,以及如何解決,這將是我下一節(jié)要闡述的內(nèi)容。

利用異或?qū)崿F(xiàn)兩個double類型變量和用戶自定義變量的交換

     Xor_Swap_2解決了利用異或不能交換兩個float數(shù)據(jù)和指針的問題,然而它卻不能正確地交換兩個double數(shù)據(jù)和兩個Person類對象。這是為什么呢?原因是函數(shù)內(nèi)部是把參數(shù)強制類型轉(zhuǎn)換成unsigned類型的,而sizeof(float)和sizeof(pointor)的值都等于sizeof(unsigned),但是sizeof(double)卻不等于sizeof(unsigned),也就是說把double強制轉(zhuǎn)換成unsigned類型時,發(fā)生了“位截斷”(在概念是區(qū)別與數(shù)據(jù)截斷),那么得到的結(jié)果肯定就不對了。至于無法交換兩個Person類對象,其原因也相同。

這里我要深入分析一下強制類型轉(zhuǎn)換是如何發(fā)生位截斷的,首先看看以下測試的輸出結(jié)果,注意代碼中的注釋,為了節(jié)約篇幅,我把值得注意的地方都放在注釋中了:

Double a = 1.0,b=2.0;

Xor_Swap_2(a,b);//交換兩個double數(shù)據(jù)

Cout<<a<<b;//輸出仍然是1.0和2.0,a,b的值并未改變

Xor_Swap_2(youngMan,oldMan);//交換兩個用戶自定義對象

youngMan.PrintSelf();//輸出young man:81

oldMan.PrintSelf();//輸出old man:18

    可以看出兩個double數(shù)據(jù)并沒被交換,而兩個Person對象在交換之后發(fā)生了怪異現(xiàn)象:產(chǎn)生了81歲的年輕人和18歲的老年人!這一點正好說明強制類型轉(zhuǎn)換時發(fā)生了位截斷,由于Person類的第一個數(shù)據(jù)成員m_Age正好是int型,在Xor_Swap_2內(nèi)部做強制類型轉(zhuǎn)換時正好取得了兩個對象的m_Age成員,于是出現(xiàn)了兩個對象被部分交換的情況,那么又如何解釋兩個double數(shù)據(jù)沒有變法呢?事實上兩個double數(shù)據(jù)仍然發(fā)生了部分交換,因為這里的兩個double數(shù)(a,b)的前4個字節(jié)正好相同,因此看不出部分交換。

既然我們知道了Xor_Swap_2為什么不能用于交換兩個double類型的數(shù)據(jù)和兩個用戶自定義的數(shù)據(jù),那么就有辦法對它進行改進。具體改進的思想就是把參數(shù)按照一個byte一個byte地分別異或,按照這個思路我實現(xiàn)了如下的函數(shù):

template <class T>
void Xor_Swap_3(T& a,T& b)
{
         
int size = sizeof(T);
         
for (int i = 0;i<size;i++)
         {
                   
*((unsigned char*)(&a)+i) = (*((unsigned char*)(&a)+i)) ^ (*((unsigned char*)(&b)+i));
                   
*((unsigned char*)(&b)+i) = (*((unsigned char*)(&a)+i)) ^ (*((unsigned char*)(&b)+i));
                   
*((unsigned char*)(&a)+i) = (*((unsigned char*)(&a)+i)) ^ (*((unsigned char*)(&b)+i));
         }
}

     這個版本的函數(shù)不僅能交換兩個整數(shù)、任何指針、float數(shù)和double數(shù),更牛逼的是它能交換兩個用戶定義類型的變量!事實上它基本上是在內(nèi)存一級上操作數(shù)據(jù),而任何類型的數(shù)據(jù)對象最終都表現(xiàn)為內(nèi)存對象。這其實就是通過內(nèi)存拷貝實現(xiàn)兩個對象的交換的一個版本吧,當(dāng)然還有利用memcpy等手段進行內(nèi)存拷貝來實現(xiàn)兩個變量的交換的,這里我就不贅述了。

結(jié)束語

    本篇到此寫完了,有種不好的感覺,因為文中大量使用“強制類型轉(zhuǎn)換”而這個東西是C++中容易出錯的地方,而我再寫本文時,并沒有去復(fù)習(xí)關(guān)于強制類型轉(zhuǎn)換的相關(guān)知識,因此擔(dān)心很多地方有潛在的出錯可能,還請各位磚家指正!

@import url(http://m.shnenglu.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

Feedback

# re: 絕對深入剖析各種方法實現(xiàn)兩個變量的交換[未登錄]  回復(fù)  更多評論   

2011-08-10 13:11 by Chipset
這不是4位機和8位機的時代了,這種交換容易出錯。如果兩個數(shù)相同這種交換是不是會出錯?大的數(shù)據(jù)結(jié)構(gòu)交換用move語義,C++0x,此時依賴大量數(shù)據(jù)拷貝的交換永遠(yuǎn)快不起來。

# re: 絕對深入剖析各種方法實現(xiàn)兩個變量的交換  回復(fù)  更多評論   

2011-08-10 17:22 by 他她女鞋
好好了解學(xué)習(xí)一下。

# re: 絕對深入剖析各種方法實現(xiàn)兩個變量的交換  回復(fù)  更多評論   

2011-08-10 21:33 by 瘋狂的面包
還是 ^ 操作 本質(zhì)還是玩這個。 我看不到有什么新意。還要注意自己和自己交換。

# re: 絕對深入剖析各種方法實現(xiàn)兩個變量的交換  回復(fù)  更多評論   

2011-08-11 13:33 by right
雖然這種探索的意義不大,樓主的探索精神還是值得表揚的。
提一個函數(shù),我沒仔細(xì)看,可能樓主用的上
float IntBitsToFloat(int x)
{
union
{
int n;
float f;
} m;
m.n = x;
return m.f;
}
int FloatToIntBits(float x)
{
union
{
float f;
int n;
} m;
m.f = x;
return m.n;
}

只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久久亚洲精品一区二区三区| 欧美xxx成人| 久久久成人精品| 午夜精品免费视频| 亚洲欧美视频在线观看| 欧美一区二区| 狼狼综合久久久久综合网 | 亚洲小说欧美另类社区| 亚洲免费观看高清在线观看| 一区二区三区日韩精品| 欧美伊人久久| 美女性感视频久久久| 欧美激情在线| 国产精品欧美在线| 国产综合精品| 最新中文字幕亚洲| 亚洲中午字幕| 鲁大师成人一区二区三区| 免费成人网www| 日韩视频一区二区三区| 午夜亚洲影视| 欧美精品日本| 国产日韩欧美二区| 99国产精品久久久久久久成人热 | 亚洲欧美日韩天堂| 久久精品最新地址| 欧美日韩国产经典色站一区二区三区 | 欧美一区免费视频| 欧美日韩中文字幕在线视频| 亚洲亚洲精品三区日韩精品在线视频 | 国产精品国产三级国产普通话蜜臀| 国产精品一级二级三级| 精品不卡视频| 亚洲欧美日韩精品综合在线观看 | 亚洲制服少妇| 欧美夫妇交换俱乐部在线观看| 亚洲精选久久| 久久久久一区二区| 国产精品久久毛片a| **性色生活片久久毛片| 欧美一区二区免费| 亚洲精品欧美专区| 免费视频一区二区三区在线观看| 国产精品一区视频| 一区二区三区精品视频| 欧美电影免费观看高清完整版| 午夜在线电影亚洲一区| 欧美日韩一区二区三区在线观看免 | 欧美一级久久久| 亚洲美女黄网| 欧美福利影院| 亚洲国产专区校园欧美| 久久久av水蜜桃| 亚洲综合首页| 国产精品久久久久久久9999 | 欧美激情一区二区三区成人| 精品不卡在线| 久久亚洲春色中文字幕| 午夜精品一区二区三区四区| 欧美亚洲不卡| 亚洲午夜久久久| 一区二区三区国产| 国产精品高潮呻吟久久av黑人| 亚洲美女淫视频| 亚洲欧洲日产国码二区| 久久成人羞羞网站| 一区二区在线观看视频| 欧美+日本+国产+在线a∨观看| 久久久久久久高潮| 在线看不卡av| 亚洲黄网站黄| 欧美视频中文一区二区三区在线观看| 99精品久久久| 亚洲理伦电影| 国产精品一区二区你懂的| 欧美亚洲一区| 欧美一区二区三区的| 一区免费在线| 好看的日韩av电影| 激情国产一区| 奶水喷射视频一区| 欧美激情精品久久久| 夜夜嗨av一区二区三区免费区| 亚洲精品乱码久久久久久| 欧美性视频网站| 久久爱91午夜羞羞| 女女同性精品视频| 亚洲免费婷婷| 久久久久久久综合色一本| 亚洲国产精品久久精品怡红院| 亚洲国产另类久久久精品极度| 欧美日韩一区在线播放| 欧美在线视频二区| 久久久亚洲影院你懂的| 一区二区毛片| 久久成人精品无人区| 一本大道久久精品懂色aⅴ| 亚洲性视频h| 91久久精品网| 亚洲在线一区| 亚洲欧洲在线一区| 亚洲欧美日韩一区二区三区在线 | 国产亚洲欧美日韩一区二区| 亚洲第一区色| 国产日韩欧美一区二区三区四区| 欧美激情导航| 国产在线不卡精品| 中文精品视频| 99re66热这里只有精品4| 先锋影音国产精品| 中文日韩电影网站| 免费看亚洲片| 久久久成人精品| 国产精品久久激情| 亚洲欧洲日本mm| 亚洲国产老妈| 欧美在线视频观看| 亚洲欧美日韩精品综合在线观看| 蜜桃久久av一区| 久久久91精品国产一区二区精品| 欧美日韩中文字幕精品| 亚洲黄色av一区| 亚洲福利电影| 欧美在线黄色| 欧美在线视频二区| 国产精品入口66mio| 亚洲人成绝费网站色www| 亚洲国产精品一区二区www在线| 欧美一区二区三区视频免费播放| 在线综合亚洲欧美在线视频| 欧美精品七区| 亚洲高清一区二区三区| 韩国av一区二区三区四区| 午夜宅男久久久| 欧美在线一二三区| 国产精品私人影院| 亚洲一级在线| 欧美亚洲免费在线| 国产日韩精品在线观看| 午夜精品av| 久久精品国产精品亚洲综合| 国产精品高潮呻吟久久| 欧美电影专区| 久久伊人亚洲| 久久aⅴ乱码一区二区三区| 欧美日韩精品中文字幕| 最新国产拍偷乱拍精品| 亚洲伦理网站| 欧美日韩一区二区三区免费看| 亚洲高清免费视频| 99日韩精品| 国产精品久久久久久久久久免费 | 激情久久久久久久久久久久久久久久| 午夜精品久久久久| 久久久久久久综合| 在线观看91精品国产麻豆| 免费欧美电影| 91久久中文字幕| 亚洲午夜精品17c| 国产伦精品一区二区三| 欧美中文字幕在线观看| 蜜桃伊人久久| 亚洲视频一区| 国产综合在线视频| 美女日韩在线中文字幕| 亚洲精品视频免费观看| 欧美在线电影| 亚洲黄色免费网站| 欧美日韩综合视频网址| 性做久久久久久| 亚洲国产精品高清久久久| 亚洲一区在线免费观看| 国产一区二区三区自拍 | 欧美乱妇高清无乱码| 国产精品99久久久久久久久| 久久精品日产第一区二区| 亚洲人体1000| 国产精品视频网址| 久久色在线播放| 亚洲色诱最新| 欧美国产日韩在线观看| 亚洲综合精品一区二区| 亚洲第一区在线观看| 国产麻豆视频精品| 欧美日韩精品国产| 久久精品国产精品亚洲| 亚洲国产精品久久久| 久久精品国产清高在天天线| 久久免费视频一区| 亚洲国产美女久久久久| 欧美香蕉大胸在线视频观看| 欧美在线视频播放| 一本色道久久综合亚洲二区三区| 久久久久国产精品一区| 一区二区三区高清视频在线观看| 黄色亚洲精品| 国产三级精品在线不卡| 欧美日韩中文另类| 欧美激情精品久久久久久久变态| 欧美中文字幕在线观看|