1. 程式人生 > >Java:遞迴 - 用遞迴實現冒泡,和解決遞迴返回值問題

Java:遞迴 - 用遞迴實現冒泡,和解決遞迴返回值問題

不能用for/while,使用遞迴實現冒泡

和for/while一樣,只是迭代的引數都要寫成傳參否則會丟失狀態

下面的程式碼loop表示每次的冒泡遍歷次數,執行時依次遞減。

遞迴冒泡程式碼:

/*
   * a recursive way of bubbleSort
   *@param arr
   *the input array of int
   *@param i
   *the current index of arr
   *@param loop
   *maximum loops needed for each traverse,started at arr.length-1
   *,ended at 1
   *@param swap
   *an indicator which shall be false when starting the sort
   *, showing if a swap happens
   */
public static void bubbleSort(int[] arr, int i, int loop, boolean swap){ if(loop>=1){ if(i<loop){ if (arr[i]>arr[i+1]){ int tmp =arr[i+1]; arr[i+1]= arr[i]; arr[i] = tmp; swap = true; } //inner loop bubbleSort
(arr,++i,loop,swap); }else{ if (!swap){ return; } //reset i and swap,redo outer loop with one less time bubbleSort(arr,0,--loop,false); System.out.println(loop); } } }

測試:

int[] arr = {41,21,5,78,13,12,41,1,4,3,4,7,9,9,10,84,72,17,
85,100,1,66,23}; bubbleSort(arr,0,arr.length-1,false); System.out.println("/n"+Arrays.toString(arr));

輸出:

3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
[1, 1, 3, 4, 4, 5, 7, 9, 9, 10, 12, 13, 17, 21, 23, 41, 41, 66, 72, 78, 84, 85, 100]

思考:輸出看起來loop是遞增的,但是按照寫的程式碼順序執行,引數loop不應該是遞減的麼?

bubbleSort(arr,0,--loop,false);
System.out.println(loop);

可以這樣思考,虛擬機器棧執行bubbleSort(arr,0,–loop,false)時,後面的執行語句都在棧底中斷未執行,此時遞迴函式又壓入了一系列執行語句…操作棧按先進後出的方式執行,當然最後輸出的是最先壓入未被執行的語句。

總結:在遞迴函式方法體內,出現在遞迴函式後面的語句會倒序輸出結果。

引申問題:遞迴函式若有返回值,會返回第一次遞迴函式的。

由於遞迴函式最後一次遞迴的返回值會被之前的不斷覆蓋,我們得到的往往不是想要的返回值。

比如我們想要用遞迴累加一個數a,loop次:

  public static int accumulation(int a, int loop){
    if(loop>0){
      a = a*2;
      accumulation(a,--loop);
    }else{
      return a;
    }
    return a;
  }

上面的函式是錯誤的,讓a=1,不管引數loop怎麼變,返回值總是2
怎麼辦呢?
其實就是找個物件存這個數,可以是基本型別,也可以是引用類,但作用域一定是大於函式傳參的。

解決方案:遞迴函式若有返回值,該返回值為成員(全域性)變數

  public class Accumulation{
  	 private static int result = 0;
	
	 public static int accumulation(int a, int loop){
    	 if(loop>0){
     		a = a*2;
     		accumulation(a,--loop);
     	}else{
     		result = a;
      		return result;
    	}
    	return result;
  	}
  }

a=1,loop=10,上面的函式返回就是1024了。

當然,如果只是測試函式輸入輸出,也可以main函式內另設靜態引用變數比如一個Collection實現類,函式增加這個傳參去存這個遞迴輸出(Object和Integer等包裝類不行)。