上一篇文章:怎麼從細節中提高python代碼質量?今天我們來聊聊中間變量。
我們提到,在數據交換值的時候,不推薦使用中間變量,那怎麼來交換兩個變量的值呢?
在我們編碼初期我們是這麼解決的:定義一個新的變量,利用它來完成交換。
初期我們可以這麼去做,因為這樣非常好理解,但是它的缺點也很明顯,因為使用了臨時變量,這樣實在浪費資源。
那麼有沒有辦法不利用這個「第三者」呢,答案是必須的!
接下來我給大家通過四種方法(算法)來實現。
算術運算;指針地址操作;位運算;棧實現。1.算術運算,代碼如下:
原理:把m、n看作數軸上的點,圍繞兩點間的距離來進行計算。
2.指針地址操作,代碼如下:
原理:對地址的操作實際上進行的是整數運算
理論上我們是通過運用算術算法類似的運算來實現地址的交換,從而達到交換變量的目的。即:
通過運算m、n的地址果然完成了交換,且m指向了原先n指向的值,n指向原先m指向的值了嗎?上面的代碼可以通過編譯,但是執行結果發生錯誤!怎麼回事啊?兄弟別急,先了解一個概念,作業系統把內存分為幾個區域:
系統代碼/數據區、應用程式代碼/數據區、堆棧區、全局數據區等等。在編譯源程序時,常量、全局變量等都會被放入全局數據區,局部變量、動態變量則放入堆棧區。
這樣當算法執行到「m=(int*)(n-m)」時,m的值並不是0x00000200h,而是要加上變量m所在內存區的基地址,實際的結果就是:0x008f0200h,其中0x008f就是基地址,0200則是m在該內存區的位移。它是由編譯器自己自動添加的。因此導致以後的地址計算都不正確,使得m,n指向所在區的其他內存單元。再者,地址運算不能出現負數,即當m的地址大於n的地址時,n-m就會小於零,系統自動採用補碼的形式表示負的位移,由此會產生錯誤,導致與前面同樣的結果。
那怎麼辦呢,別急!以下是整改後的算法:
算法做的最大改進就是採用位運算中的與運算「int(m)&0x0000ffff",因為地址中高16位為段地址,後16位為位移地址,將它和0x0000ffff進行與運算後,段地址被屏蔽,只保留位移地址。這樣就原始算法吻合,從而得到正確的結果。
大家看著可能有點不好理解,但是他的好處是:即在交換很大的數據類型時,執行速度比算術算法快。
3.位運算,代碼如下:
此算法能夠實現是由異或運算的特點決定的,通過異或運算能夠使數據中的某些位翻轉,其他位不變。這就意味著任意一個數與任意一個給定的值連續異或兩次,值不變。
4.棧實現,代碼如下:
以上算法均實現了不藉助其他變量來完成兩個變量值的交換,相比較而言算術算法和位算法計算量相當,地址算法中計算較複雜,卻可以很輕鬆地實現大類型(比如自定義的類或結構)的交換。
而從實際的軟體開發看,標準算法無疑是最好的,能夠解決任意類型的交換問題。