遞迴就是程式在執行的過程中呼叫自己(用自己定義自己)
遞迴的三要素:邊界條件
遞迴前進段
遞迴返回段
遞迴和棧
遞迴和棧有這緊密的聯絡,大多數編譯器都是使用棧來實現遞迴的,當呼叫方法時,編譯器會把這個方法的所有引數和返回位址都壓入棧中,然後把控制轉移給這個方法。當方法返回時,這些值退棧。引數消失了,並且控制權重新回到返回位址處。
呼叫乙個方法時,所進行的步驟:
1)當乙個方法被呼叫時,它的引數和返回位址壓入棧中
2)這個方法可以通過獲取棧頂元素訪問引數
3)當這個方法返回時,它檢視棧已獲取返回位址,然後這個位址和所有引數退棧,並且銷毀
下圖是求階乘的圖示,幫助理解:
* 求整數n的階乘3*
4* @param
n 整數n5*
@return6*/
7public
static
int factorial(int
n) 11
if (n == 1 || n == 0) else
16 }
1漢諾塔問題是乙個經典的問題。漢諾塔(hanoi tower),又稱河內塔,源於印度乙個古老傳說。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片**圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,任何時候,在小圓盤上都不能放大圓盤,且在三根柱子之間一次只能移動乙個圓盤。問應該如何操作?/**2
* 二分法遞迴,找目標值位置
3* 查詢的陣列一定是有序的4*
@param
array 有序陣列5*
@param
start 起始位置6*
@param
end 結束位置7*
@param
target 目標值8*
@return
返回-1代表沒找到目標值9*/
1011
public
static
int dichotomy(int array, int start, int end, int
target) else
if (start >=end) else
if (array[mid] >target) else
if (array[mid]
22return -1;
23 }
問題分析:
假設a最下邊的盤子為n,如果想把n移動到目標c上,需要先把n-1到n的盤子整體挪到b上,再把n移到c上。此時將b和a交位置,忽略c上的盤子,則移動n個盤子的問題轉變為移動n-1個盤子的問題。依次類推,最終簡化為移動兩個盤子的問題。
總結規律:
移動n個盤子所需的總步驟為:2n-1步
**實現:
1計算xy相當於y個x相乘,用二分法的思想,每次都將y分成兩半,此時就有奇偶的問題需要注意。/**2
* 漢諾塔問題3*
@param
n 盤子個數(也表示名稱) 盤子從大->小編號依次為 1->n4*
@param
from 初始塔座5*
@param
temp 中介塔座6*
@param
to 目標塔座7*/
8public
static
void hanoi(int
n, string from, string temp, string to) else16}
1718
public
static
void
move(string from, string to) 移動到 {}", from, to);
20 }
**實現如下:
1問題:有多種不同重量的揹包,假如你想要乙個20kg揹包,你可以有多種選擇方式。/**2
* 求 num 的 pow次方3*/
4public
static
int mypow(int num, int
pow)
8if (pow % 2 == 1) else
13 }
解析:其實這是乙個排列組合問題,將揹包按任意順序排列a、b、c、d、e,從第乙個揹包開始,此時你有兩個選擇,要麼選擇a要不不選擇a,選擇a的話你需要從剩下的揹包裡選20-a的重量,不選擇a的話你需要從剩下的揹包裡選擇20的重量。不論你是否選擇a揹包,你面對揹包b的時候同樣面臨兩個選擇,以此類推,當你遍歷到最後乙個揹包時已經遍歷的所有的場景。當你需要從剩下的揹包中選擇0的重量時,說明你現在選擇的揹包滿足要求,不能再選。當你需要從剩下的揹包中選擇負數的重量時,說明你如果選擇現有的揹包,那麼你不可能選到符合要求的揹包,需要跳過。
**實現:
public輸出結果:class
knapsack
/*** 選擇組合方式
* @param
weight 目標重量
* @param
index 開始索引(從第幾個開始選,前邊的不選)
*/private
void select(int weight, int
index)
}system.out.println();
return
; }
if (weight < 0 || index >=weights.length)
//選擇該重量
selects[index] = true
; select(weight - weights[index], index + 1);
//不選擇該重量
selects[index] = false
; select(weight, index + 1);
}public
static
void
main(string args) ;
knapsack k = new
knapsack(a);
k.select(20, 0);}}
從n個人中選擇m個人最為你的隊友,此問題與揹包問題相同,解析方法類似。
**實現:
1輸出結果:/**2
* 選擇隊員
3* 1、從n個人中選擇m個隊員,例如從5個人中選擇3個記錄為(5,3)
4* 2、假設從第乙個人開始選擇,那麼分為選擇和不選擇兩種情況,即為(5,3)=(4,2)+(4,3)依次類推5*/
678public
class
selectteam
1617
/**18
* 選擇隊員
19*
@param
num 要選擇的隊員數
20*
@param
index 從第幾個開始選
21*/
22public
void select(int num,int
index)29}
30system.out.println();
31return;32
}3334if (num < 0 || index > persons.length-1)
3738
//選擇第乙個人
39 selects[index]=true
;40 select(num-1,index+1);
41//
不選擇第乙個人
42 selects[index]=false
;43 select(num,index+1);44}
4546
public
static
void
main(string args) ;
48 selectteam selectteam=new
selectteam(person);
49 selectteam.select(3,0);50}
51 }
遞迴演算法的應用
提起漢諾塔,大家都會想起遞迴程式,大家都知道遞迴程式的實現是用棧來實現的,但是,有些程式是需要用到棧,但是我們還要編寫一棧的資料結構,挺麻煩的,所以,用遞迴程式實現起來是很簡單的!1.學習資料結構時,講到迷宮演算法,是用棧實現的,如果用遞迴演算法實現會更簡單的.掃雷程式也是實行遞迴搜尋的.對於迷宮程...
遞迴演算法簡單應用
1.遞迴和非遞迴分別實現求第n個斐波那契數。斐波那契數 亦稱之為斐波那契數列 義大利語 successione di fibonacci 又稱 分割數列 費波那西數列 費波拿契數 費氏數列,指的是這樣乙個數列 1 1 2 3 5 8 13 21 在數學上,斐波那契數列以如下被以遞迴的方法定義 f0 ...
遞迴演算法應用例項 八皇后演算法
回溯演算法的經典案例 回溯演算法的典型案例。該問題是國際西洋棋棋手馬克斯.貝瑟爾於1848年提出 在8x8格的西洋棋上擺放八個皇后,使其不能互相攻擊,即 任意兩個皇后都不能外乾同一行 同一列或同一斜線上,問有多少種擺法。思路分析 第乙個皇后先放在第一行第一列 第二個皇后放在第二行第一列 然後判斷是否...