20200913 第 6 章 遞迴

2022-03-18 03:52:31 字數 3475 閱讀 8630

看個實際應用場景, 迷宮問題(回溯), 遞迴(recursion)

簡單的說: 遞迴就是方法自己呼叫自己,每次呼叫時傳入不同的變數.遞迴有助於程式設計者解決複雜的問題,同時可以讓**變得簡潔。

列舉兩個小案例,回顧一下遞迴呼叫機制

列印問題

階乘問題

使用**方式說明了遞迴的呼叫機制

public class recursiontest 

public static void test(int n)

// !!!當有 else 時,結果不同

//else }}

public static int factorial(int n)  else 

}

遞迴用於解決什麼樣的問題

各種數學問題如: 8 皇后問題 , 漢諾塔, 階乘問題, 迷宮問題, 球和籃子的問題(google 程式設計大賽)

各種演算法中也會使用到遞迴, 比如快排, 歸併排序, 二分查詢, 分治演算法等

將用棧解決的問題 --> 遞迴**比較簡潔

遞迴需要遵守的重要規則:

執行乙個方法時, 就建立乙個新的受保護的獨立空間(棧空間)

方法的區域性變數是獨立的, 不會相互影響, 比如 n 變數

如果方法中使用的是引用型別變數(比如陣列), 就會共享該引用型別的資料.

遞迴必須向退出遞迴的條件逼近, 否則就是無限遞迴,出現 stackoverflowerror

當乙個方法執行完畢, 或者遇到 return, 就會返回, 遵守誰呼叫, 就將結果返回給誰, 同時當方法執行完畢或者返回時, 該方法也就執行完畢

從 (1,1) 開始,小球走到右下角 (6,5)

public class mymigong 

/*** 使用遞迴回溯來給小球找路

* 說明

* 1. map 表示地圖

* 2. i,j 表示從地圖的哪個位置開始出發 (1,1)

* 3. 如果小球能到 map[6][5] 位置,則說明通路找到.

* 4. 約定: 當map[i][j] 為 0 表示該點沒有走過 當為 1 表示牆 ; 2 表示通路可以走 ; 3 表示該點已經走過,但是走不通

* 5. 在走迷宮時,需要確定乙個策略(方法) 下->右->上->左 , 如果該點走不通,再回溯

** @param map

* @param i

* @param j

* @return 如果找到通路,就返回true, 否則返回false

*/private static boolean setway(int map, int i, int j) else else if (setway(map, i, j + 1)) else if (setway(map, i - 1, j)) else if (setway(map, i, j - 1)) else

} else }}

private static int initmap()

// 左右全部置為1

for (int i = 0; i < 8; i++)

//設定擋板, 1 表示

map[3][1] = 1;

map[3][2] = 1;

// map[1][2] = 1;

// map[2][2] = 1;

return map;

}private static void printmap(int map)

system.out.println();}}

}

再得到小球路徑時, 可以先使用(下右上左), 再改成(上右下左), 看看路徑是不是有變化

測試回溯現象

思考: 如何求出最短路徑? 思路 --> **實現.

八皇后問題, 是乙個古老而著名的問題, 是回溯演算法的典型案例。 該問題是國際西洋棋棋手馬克斯· 貝瑟爾於 1848 年提出: 在 8×8 格的西洋棋上擺放八個皇后, 使其不能互相攻擊, 即: 任意兩個皇后都不能處於同一行、同一列或同一斜線上, 問有多少種擺法 (92)。

第乙個皇后先放第一行第一列

第二個皇后放在第二行第一列、 然後判斷是否 ok, 如果不 ok, 繼續放在第二列、 第三列、 依次把所有列都放完, 找到乙個合適

繼續第三個皇后, 還是第一列、 第二列……直到第 8 個皇后也能放在乙個不衝突的位置, 算是找到了乙個正確解

當得到乙個正確解時, 在棧回退到上乙個棧時, 就會開始回溯, 即將第乙個皇后, 放到第一列的所有正確解,全部得到.

然後回頭繼續第乙個皇后放第二列, 後面繼續迴圈執行 1,2,3,4 的步驟

說明:理論上應該建立乙個二維陣列來表示棋盤, 但是實際上可以通過演算法, 用乙個一維陣列即可解決問題.

arr[8] =

對應 arr 下標 表示第幾行, 即第幾個皇后, arr[i] = val , val 表示第 i+1 個皇后, 放在第 i+1 行的第 val+1 列

public class myqueen8 

int array = new int[max];

static int count = 0;

static int judgecount = 0;

static int countarr = new int[8];

static int x = 0;

public static void main(string args)

//編寫乙個方法,放置第n個皇后

//特別注意: check 是 每一次遞迴時,進入到check中都有 for(int i = 0; i < max; i++),因此會有回溯

private void check(int n)

//依次放入皇后,並判斷是否衝突

for (int i = 0; i < max; i++)

//如果衝突,就繼續執行 array[n] = i; 即將第n個皇后,放置在本行得 後移的乙個位置

if (n == 0) else

x++;}}

}private int calc(int arr, int n) else

}/**

* 檢視當我們放置第n個皇后, 就去檢測該皇后是否和前面已經擺放的皇后衝突

* * @param n 表示第n個皇后

* @return

*/private boolean judge(int n)

}return true;

}//寫乙個方法,可以將皇后擺放的位置輸出

private void print()

system.out.println();}}

第5章 遞迴

目錄 四 遞迴程式設計的應用例項 大綱未規定 五 演算法設計題 六 錯題集 資料結構與演算法 師大完整教程目錄 更有python go pytorch tensorflow 爬蟲 人工智慧教學等著你 遞迴 直接或間接的呼叫函式本身 遞迴程式的兩個特點 具備遞迴出口 在不滿足遞迴出口的情況下,把原問題...

第 6章 函式

6.1.2引數 2.引數陣列 c 允許為函式指定乙個 只能乙個 特殊的引數,這個引數必須是函式定義中的最後乙個引數,可用params關鍵字定義他們 如 params int vals 3.引用引數和值引數 理解 將本來在函式中引數按值引用的規則改變成按傳遞引用,使得這個引數會改變,定義引數和傳遞引數...

第6章 函式

1.自動物件 只存在於塊執行期間的物件 2.區域性靜態物件static 在程式執行路徑第一次經過物件定義語句時初始化,並且知道程式終止才被銷毀,如果區域性靜態變數沒有顯示的初始值,初始化為0.3.如果函式無須改變引用形參的值,最好將其生命為常量引用。4.使用引用形參返回額外資訊 5.和其他初始化過程...