Swap in C C++ C# Java


寫一個函數交換兩個變量的值。

C:

錯誤的實現:

void swap(int i, int j) 
{
   int t = i;
   i = j;
   j = t;
}

因為C語言的函數參數是以值來傳遞的(pass by value),參數傳遞時被copy了,所以函數中交換的是復制后的值。

正確的實現:

指針版:

void swap(int *i, int *j) 
{
   int t = *i;
   *i = *j;
   *j = t;
}

函數使用時候傳遞的是變量的地址,如 swap(&a,&b),函數交換的是兩個指針指向的值,就是兩個變量的值,所以交換成功。

預處理版:

#define swap(type, i, j) {type t = i; i = j; j = t;}

預處理的實質是文本替換(textual substitution)。

如下代碼:

#define swap(type, i, j) {type t = i; i = j; j = t;}

int main() 
{
    int a = 23, b = 47;
    printf("Before swap. a: %d, b: %d\n", a, b);
    swap(int, a, b)
    printf("After swap.  a: %d, b: %d\n", a, b);
    return 0;
}

預處理之后的代碼就是:

int main() 
{
    int a = 23, b = 47;
    printf("Before swap. a: %d, b: %d\n", a, b);
     { int t = a ; a = b ; b = t ; }
    printf("After swap.  a: %d, b: %d\n", a, b);
    return 0;
}

所以可以正確的交換兩個變量的值。

C++:

方式一:如同C語言使用指針。
方式二:使用“引用”(&)

void swap(int& i, int& j) 
{
    int t = i;
    i = j;
    j = t;
}

C++的函數參數使用引用(&),值通過引用傳遞(pass by reference),函數中的參數不被 copy(如果傳的是類就不會調用拷貝構造函數),所以在函數中能正確交換兩個變量的值。

C#:

static void Swap<T>(ref T lhs, ref T rhs)
{
    T temp;
    temp = lhs;
    lhs = rhs;
    rhs = temp;
}

不要忘了ref關鍵字,如果沒有是不能正確交換的!

Java:

java.util.Collections;
public static void swap(List<?> list,int i,int j)

使用集合中的static方法。

如果不使用數組集合,Java中沒有一個簡單的函數來交換兩個變量的值。除非自己封裝一下:

// MyInteger: similar to Integer, but can change value
class MyInteger {
   private int x;                   // single data member
   public MyInteger(int xIn) { x = xIn; } // constructor
   public int getValue() { return x; }  // retrieve value
   public void insertValue(int xIn) { x = xIn;} // insert
}

public class Swapping {
   // swap: pass references to objects
   static void swap(MyInteger rWrap, MyInteger sWrap) {
      // interchange values inside objects
      int t = rWrap.getValue();
      rWrap.insertValue(sWrap.getValue());
      sWrap.insertValue(t);
   }

   public static void main(String[] args) {
      int a = 23, b = 47;
      System.out.println("Before. a:" + a + ", b: " + b);
      MyInteger aWrap = new MyInteger(a);
      MyInteger bWrap = new MyInteger(b);
      swap(aWrap, bWrap);
      a = aWrap.getValue();
      b = bWrap.getValue();
      System.out.println("After.  a:" + a + ", b: " + b);
   }
}

C#這點和Java是一樣的,C#版的交換如果不使用ref關鍵字,swap函數也沒法正確工作。

雖然C#、java通過函數參數可以修改參數的值,但是這點和C++的引用有很大的區別。

看看如下函數:

public void tricky(Point arg1, Point arg2)
{
    arg1.x = 100;
    arg1.y = 100;
    Point temp = arg1;
    arg1 = arg2;
    arg2 = temp;
}
 
public static void main(String [] args)
{
    Point pnt1 = new Point(0,0);
    Point pnt2 = new Point(0,0);
    System.out.println("X: " + pnt1.x + " Y: " +pnt1.y);
    System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
    System.out.println(" ");
    tricky(pnt1,pnt2);
    System.out.println("X: " + pnt1.x + " Y:" + pnt1.y);
    System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
}

執行這個函數,將得到以下輸出:

———————————————————-
X: 0 Y: 0
X: 0 Y: 0

X: 100 Y: 100
X: 0 Y: 0
———————————————————-

當Java傳遞對象給函數之后,兩個引用指向了同一對象:

當被傳遞給函數之后,一個對象至少存在兩個引用

Java復制並傳遞了“引用”的值,而不是對象。因此,方法中對對象的計算是會起作用的,因為引用指向了原來的對象。但是因為方法中對象的引用是“副本”,所以對象交換就沒起作用。如下圖所示,交換動作只對方法中的引用副本起作用了,不影響方法外的引用。所以不好意思,方法被調用后,改變不了方法外的對象的引用。如果要對方法外的對象引用做交換,我們應該交換原始的引用,而不是它的副本。

只有傳入函數的引用交換了,原始引用則沒有。

 

參考: 

http://www.cs.utsa.edu/~wagner/CS2213/swap/swap.html
http://stackoverflow.com/questions/1363186/is-it-possible-to-write-swap-method-in-java
http://www.importnew.com/3559.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM