日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java break递归_【Java】递归总结

發(fā)布時間:2025/3/15 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java break递归_【Java】递归总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

摘要:

大師 L. Peter Deutsch 說過:To Iterate is Human, to Recurse, Divine.中文譯為:人理解迭代,神理解遞歸。毋庸置疑地,遞歸確實是一個奇妙的思維方式。對一些簡單的遞歸問題,我們總是驚嘆于遞歸描述問題的能力和編寫代碼的簡潔,但要想真正領(lǐng)悟遞歸的精髓、靈活地運用遞歸思想來解決問題卻并不是一件容易的事情。本文剖析了遞歸的思想內(nèi)涵,分析了遞歸與循環(huán)的聯(lián)系與區(qū)別,給出了遞歸的應(yīng)用場景和一些典型應(yīng)用,并利用遞歸和非遞歸的方式解決了包括階乘、斐波那契數(shù)列、漢諾塔、楊輝三角的存取、字符串回文判斷、字符串全排列、二分查找、樹的深度求解在內(nèi)的八個經(jīng)典問題。

版權(quán)聲明:

友情提示:

若讀者需要本博文相關(guān)完整代碼,請移步我的Github自行獲取,項目名為 SwordtoOffer,鏈接地址為:https://github.com/githubofrico/SwordtoOffer。

一. 引子

大師 L. Peter Deutsch 說過:To Iterate is Human, to Recurse, Divine.中文譯為:人理解迭代,神理解遞歸。毋庸置疑地,遞歸確實是一個奇妙的思維方式。對一些簡單的遞歸問題,我們總是驚嘆于遞歸描述問題的能力和編寫代碼的簡潔,但要想真正領(lǐng)悟遞歸的精髓、靈活地運用遞歸思想來解決問題卻并不是一件容易的事情。在正式介紹遞歸之前,我們首先引用知乎用戶李繼剛(https://www.zhihu.com/question/20507130/answer/15551917)對遞歸和循環(huán)的生動解釋:

遞歸:你打開面前這扇門,看到屋里面還有一扇門。你走過去,發(fā)現(xiàn)手中的鑰匙還可以打開它,你推開門,發(fā)現(xiàn)里面還有一扇門,你繼續(xù)打開它。若干次之后,你打開面前的門后,發(fā)現(xiàn)只有一間屋子,沒有門了。然后,你開始原路返回,每走回一間屋子,你數(shù)一次,走到入口的時候,你可以回答出你到底用這你把鑰匙打開了幾扇門。

循環(huán):你打開面前這扇門,看到屋里面還有一扇門。你走過去,發(fā)現(xiàn)手中的鑰匙還可以打開它,你推開門,發(fā)現(xiàn)里面還有一扇門(若前面兩扇門都一樣,那么這扇門和前兩扇門也一樣;如果第二扇門比第一扇門小,那么這扇門也比第二扇門小,你繼續(xù)打開這扇門,一直這樣繼續(xù)下去直到打開所有的門。但是,入口處的人始終等不到你回去告訴他答案。

上面的比喻形象地闡述了遞歸與循環(huán)的內(nèi)涵,那么我們來思考以下幾個問題:

什么是遞歸呢?

遞歸的精髓(思想)是什么?

遞歸和循環(huán)的區(qū)別是什么?

什么時候該用遞歸?

使用遞歸需要注意哪些問題?

遞歸思想解決了哪些經(jīng)典的問題?

這些問題正是筆者準備在本文中詳細闡述的問題。

二. 遞歸的內(nèi)涵

1、定義 (什么是遞歸?)

在數(shù)學(xué)與計算機科學(xué)中,遞歸(Recursion)是指在函數(shù)的定義中使用函數(shù)自身的方法。實際上,遞歸,顧名思義,其包含了兩個意思:遞 和 歸,這正是遞歸思想的精華所在。

2、遞歸思想的內(nèi)涵(遞歸的精髓是什么?)

正如上面所描述的場景,遞歸就是有去(遞去)有回(歸來),如下圖所示?!坝腥ァ笔侵?#xff1a;遞歸問題必須可以分解為若干個規(guī)模較小,與原問題形式相同的子問題,這些子問題可以用相同的解題思路來解決,就像上面例子中的鑰匙可以打開后面所有門上的鎖一樣;“有回”是指 : 這些問題的演化過程是一個從大到小,由近及遠的過程,并且會有一個明確的終點(臨界點),一旦到達了這個臨界點,就不用再往更小、更遠的地方走下去。最后,從這個臨界點開始,原路返回到原點,原問題解決。

更直接地說,遞歸的基本思想就是把規(guī)模大的問題轉(zhuǎn)化為規(guī)模小的相似的子問題來解決。特別地,在函數(shù)實現(xiàn)時,因為解決大問題的方法和解決小問題的方法往往是同一個方法,所以就產(chǎn)生了函數(shù)調(diào)用它自身的情況,這也正是遞歸的定義所在。格外重要的是,這個解決問題的函數(shù)必須有明確的結(jié)束條件,否則就會導(dǎo)致無限遞歸的情況。

3、用歸納法來理解遞歸

數(shù)學(xué)都不差的我們,第一反應(yīng)就是遞歸在數(shù)學(xué)上的模型是什么,畢竟我們對于問題進行數(shù)學(xué)建模比起代碼建模拿手多了。觀察遞歸,我們會發(fā)現(xiàn),遞歸的數(shù)學(xué)模型其實就是 數(shù)學(xué)歸納法,這個在高中的數(shù)列里面是最常用的了,下面回憶一下數(shù)學(xué)歸納法。

數(shù)學(xué)歸納法適用于將解決的原問題轉(zhuǎn)化為解決它的子問題,而它的子問題又變成子問題的子問題,而且我們發(fā)現(xiàn)這些問題其實都是一個模型,也就是說存在相同的邏輯歸納處理項。當然有一個是例外的,也就是歸納結(jié)束的那一個處理方法不適用于我們的歸納處理項,當然也不能適用,否則我們就無窮歸納了。總的來說,歸納法主要包含以下三個關(guān)鍵要素:

步進表達式:問題蛻變成子問題的表達式

結(jié)束條件:什么時候可以不再使用步進表達式

直接求解表達式:在結(jié)束條件下能夠直接計算返回值的表達式

事實上,這也正是某些數(shù)學(xué)中的數(shù)列問題在利用編程的方式去解決時可以使用遞歸的原因,比如著名的斐波那契數(shù)列問題。

4、遞歸的三要素

在我們了解了遞歸的基本思想及其數(shù)學(xué)模型之后,我們?nèi)绾尾拍軐懗鲆粋€漂亮的遞歸程序呢?筆者認為主要是把握好如下三個方面:

1、明確遞歸終止條件;

2、給出遞歸終止時的處理辦法;

3、提取重復(fù)的邏輯,縮小問題規(guī)模。

1). 明確遞歸終止條件

我們知道,遞歸就是有去有回,既然這樣,那么必然應(yīng)該有一個明確的臨界點,程序一旦到達了這個臨界點,就不用繼續(xù)往下遞去而是開始實實在在的歸來。換句話說,該臨界點就是一種簡單情境,可以防止無限遞歸。

2). 給出遞歸終止時的處理辦法

我們剛剛說到,在遞歸的臨界點存在一種簡單情境,在這種簡單情境下,我們應(yīng)該直接給出問題的解決方案。一般地,在這種情境下,問題的解決方案是直觀的、容易的。

3). 提取重復(fù)的邏輯,縮小問題規(guī)模*

我們在闡述遞歸思想內(nèi)涵時談到,遞歸問題必須可以分解為若干個規(guī)模較小、與原問題形式相同的子問題,這些子問題可以用相同的解題思路來解決。從程序?qū)崿F(xiàn)的角度而言,我們需要抽象出一個干凈利落的重復(fù)的邏輯,以便使用相同的方式解決子問題。

5、遞歸算法的編程模型

在我們明確遞歸算法設(shè)計三要素后,接下來就需要著手開始編寫具體的算法了。在編寫算法時,不失一般性,我們給出兩種典型的遞歸算法設(shè)計模型,如下所示。

模型一: 在遞去的過程中解決問題

function recursion(大規(guī)模){

if (end_condition){ // 明確的遞歸終止條件

end; // 簡單情景

}else{ // 在將問題轉(zhuǎn)換為子問題的每一步,解決該步中剩余部分的問題

solve; // 遞去

recursion(小規(guī)模); // 遞到最深處后,不斷地歸來

}

}

模型二: 在歸來的過程中解決問題

function recursion(大規(guī)模){

if (end_condition){ // 明確的遞歸終止條件

end; // 簡單情景

}else{ // 先將問題全部描述展開,再由盡頭“返回”依次解決每步中剩余部分的問題

recursion(小規(guī)模); // 遞去

solve; // 歸來

}

}

6、遞歸的應(yīng)用場景

在我們實際學(xué)習(xí)工作中,遞歸算法一般用于解決三類問題:

(1). 問題的定義是按遞歸定義的(Fibonacci函數(shù),階乘,…);

(2). 問題的解法是遞歸的(有些問題只能使用遞歸方法來解決,例如,漢諾塔問題,…);

(3). 數(shù)據(jù)結(jié)構(gòu)是遞歸的(鏈表、樹等的操作,包括樹的遍歷,樹的深度,…)。

在下文我們將給出遞歸算法的一些經(jīng)典應(yīng)用案例,這些案例基本都屬于第三種類型問題的范疇。

三. 遞歸與循環(huán)

遞歸與循環(huán)是兩種不同的解決問題的典型思路。遞歸通常很直白地描述了一個問題的求解過程,因此也是最容易被想到解決方式。循環(huán)其實和遞歸具有相同的特性,即做重復(fù)任務(wù),但有時使用循環(huán)的算法并不會那么清晰地描述解決問題步驟。單從算法設(shè)計上看,遞歸和循環(huán)并無優(yōu)劣之別。然而,在實際開發(fā)中,因為函數(shù)調(diào)用的開銷,遞歸常常會帶來性能問題,特別是在求解規(guī)模不確定的情況下;而循環(huán)因為沒有函數(shù)調(diào)用開銷,所以效率會比遞歸高。遞歸求解方式和循環(huán)求解方式往往可以互換,也就是說,如果用到遞歸的地方可以很方便使用循環(huán)替換,而不影響程序的閱讀,那么替換成循環(huán)往往是好的。問題的遞歸實現(xiàn)轉(zhuǎn)換成非遞歸實現(xiàn)一般需要兩步工作:

(1). 自己建立“堆棧(一些局部變量)”來保存這些內(nèi)容以便代替系統(tǒng)棧,比如樹的三種非遞歸遍歷方式;

(2). 把對遞歸的調(diào)用轉(zhuǎn)變?yōu)閷ρh(huán)處理。

特別地,在下文中我們將給出遞歸算法的一些經(jīng)典應(yīng)用案例,對于這些案例的實現(xiàn),我們一般會給出遞歸和非遞歸兩種解決方案,以便讀者體會。

四. 經(jīng)典遞歸問題實戰(zhàn)

第一類問題:問題的定義是按遞歸定義的

(1). 階乘

/**

* Title: 階乘的實現(xiàn)

* Description:

* 遞歸解法

* 非遞歸解法

*@author rico

*/

public class Factorial {

/**

*@description 階乘的遞歸實現(xiàn)

*@author rico

*@created 2017年5月10日 下午8:45:48

*@param n

*@return

*/

public static long f(int n){

if(n == 1) // 遞歸終止條件

return 1; // 簡單情景

return n*f(n-1); // 相同重復(fù)邏輯,縮小問題的規(guī)模

}

--------------------------------我是分割線-------------------------------------

/**

*@description 階乘的非遞歸實現(xiàn)

*@author rico

*@created 2017年5月10日 下午8:46:43

*@param n

*@return

*/

public static long f_loop(int n) {

long result = n;

while (n > 1) {

n--;

result = result * n;

}

return result;

}

}1

(2). 斐波納契數(shù)列

/**

* Title: 斐波納契數(shù)列

*

* Description: 斐波納契數(shù)列,又稱黃金分割數(shù)列,指的是這樣一個數(shù)列:1、1、2、3、5、8、13、21、……

* 在數(shù)學(xué)上,斐波納契數(shù)列以如下被以遞歸的方法定義:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)。

*

* 兩種遞歸解法:經(jīng)典解法和優(yōu)化解法

* 兩種非遞歸解法:遞推法和數(shù)組法

*

* @author rico

*/

public class FibonacciSequence {

/**

*@description 經(jīng)典遞歸法求解

*

* 斐波那契數(shù)列如下:

*

* 1,1,2,3,5,8,13,21,34,...

*

* *那么,計算fib(5)時,需要計算1次fib(4),2次fib(3),3次fib(2),調(diào)用了2次fib(1)*,即:

*

* fib(5) = fib(4) + fib(3)

*

* fib(4) = fib(3) + fib(2) ;fib(3) = fib(2) + fib(1)

*

* fib(3) = fib(2) + fib(1)

*

* 這里面包含了許多重復(fù)計算,而實際上我們只需計算fib(4)、fib(3)、fib(2)和fib(1)各一次即可,

* 后面的optimizeFibonacci函數(shù)進行了優(yōu)化,使時間復(fù)雜度降到了O(n).

*

*@author rico

*@created 2017年5月10日 下午12:00:42

*@param n

*@return

*/

public static int fibonacci(int n) {

if (n == 1 || n == 2) { // 遞歸終止條件

return 1; // 簡單情景

}

return fibonacci(n - 1) + fibonacci(n - 2); // 相同重復(fù)邏輯,縮小問題的規(guī)模

}

——————————–我是分割線————————————-

/**

* @description 對經(jīng)典遞歸法的優(yōu)化

*

* 斐波那契數(shù)列如下:

*

* 1,1,2,3,5,8,13,21,34,...

*

* 那么,我們可以這樣看:fib(1,1,5) = fib(1,2,4) = fib(2,3,3) = 5

*

* 也就是說,以1,1開頭的斐波那契數(shù)列的第五項正是以1,2開頭的斐波那契數(shù)列的第四項,

* 而以1,2開頭的斐波那契數(shù)列的第四項也正是以2,3開頭的斐波那契數(shù)列的第三項,

* 更直接地,我們就可以一步到位:fib(2,3,3) = 2 + 3 = 5,計算結(jié)束。

*

* 注意,前兩個參數(shù)是數(shù)列的開頭兩項,第三個參數(shù)是我們想求的以前兩個參數(shù)開頭的數(shù)列的第幾項。

*

* 時間復(fù)雜度:O(n)

*

* @author rico

* @param first 數(shù)列的第一項

* @param second 數(shù)列的第二項

* @param n 目標項

* @return

*/

public static int optimizeFibonacci(int first, int second, int n) {

if (n > 0) {

if(n == 1){ // 遞歸終止條件

return first; // 簡單情景

}else if(n == 2){ // 遞歸終止條件

return second; // 簡單情景

}else if (n == 3) { // 遞歸終止條件

return first + second; // 簡單情景

}

return optimizeFibonacci(second, first + second, n - 1); // 相同重復(fù)邏輯,縮小問題規(guī)模

}

return -1;

}

--------------------------------我是分割線-------------------------------------

/**

*@description 非遞歸解法:有去無回

*@author rico

*@created 2017年5月10日 下午12:03:04

*@param n

*@return

*/

public static int fibonacci_loop(int n) {

if (n == 1 || n == 2) {

return 1;

}

int result = -1;

int first = 1; // 自己維護的"棧",以便狀態(tài)回溯

int second = 1; // 自己維護的"棧",以便狀態(tài)回溯

for (int i = 3; i <= n; i++) { // 循環(huán)

result = first + second;

first = second;

second = result;

}

return result;

}

--------------------------------我是分割線-------------------------------------

/**

*@description 使用數(shù)組存儲斐波那契數(shù)列

*@author rico

*@param n

*@return

*/

public static int fibonacci_array(int n) {

if (n > 0) {

int[] arr = new int[n]; // 使用臨時數(shù)組存儲斐波納契數(shù)列

arr[0] = arr[1] = 1;

for (int i = 2; i < n; i++) { // 為臨時數(shù)組賦值

arr[i] = arr[i-1] + arr[i-2];

}

return arr[n - 1];

}

return -1;

}

}

(3). 楊輝三角的取值

/**

* @description 遞歸獲取楊輝三角指定行、列(從0開始)的值

* 注意:與是否創(chuàng)建楊輝三角無關(guān)

* @author rico

* @x 指定行

* @y 指定列

*/

/**

* Title: 楊輝三角形又稱Pascal三角形,它的第i+1行是(a+b)i的展開式的系數(shù)。

* 它的一個重要性質(zhì)是:三角形中的每個數(shù)字等于它兩肩上的數(shù)字相加。

*

* 例如,下面給出了楊輝三角形的前4行:

* 1

* 1 1

* 1 2 1

* 1 3 3 1

*@description 遞歸獲取楊輝三角指定行、列(從0開始)的值

* 注意:與是否創(chuàng)建楊輝三角無關(guān)

*@author rico

*@x 指定行

*@y 指定列

*/

public static int getValue(int x, int y) {

if(y <= x && y >= 0){

if(y == 0 || x == y){ // 遞歸終止條件

return 1;

}else{

// 遞歸調(diào)用,縮小問題的規(guī)模

return getValue(x-1, y-1) + getValue(x-1, y);

}

}

return -1;

}

}

(4). 回文字符串的判斷

/**

* Title: 回文字符串的判斷

* Description: 回文字符串就是正讀倒讀都一樣的字符串。如”98789”, “abccba”都是回文字符串

*

* 兩種解法:

* 遞歸判斷;

* 循環(huán)判斷;

*

* @author rico

*/

public class PalindromeString {

/**

*@description 遞歸判斷一個字符串是否是回文字符串

*@author rico

*@created 2017年5月10日 下午5:45:50

*@param s

*@return

*/

public static boolean isPalindromeString_recursive(String s){

int start = 0;

int end = s.length()-1;

if(end > start){ // 遞歸終止條件:兩個指針相向移動,當start超過end時,完成判斷

if(s.charAt(start) != s.charAt(end)){

return false;

}else{

// 遞歸調(diào)用,縮小問題的規(guī)模

return isPalindromeString_recursive(s.substring(start+1).substring(0, end-1));

}

}

return true;

}

--------------------------------我是分割線-------------------------------------

/**

*@description 循環(huán)判斷回文字符串

*@author rico

*@param s

*@return

*/

public static boolean isPalindromeString_loop(String s){

char[] str = s.toCharArray();

int start = 0;

int end = str.length-1;

while(end > start){ // 循環(huán)終止條件:兩個指針相向移動,當start超過end時,完成判斷

if(str[end] != str[start]){

return false;

}else{

end --;

start ++;

}

}

return true;

}

}

(5). 字符串全排列

遞歸解法

/**

* @description 從字符串數(shù)組中每次選取一個元素,作為結(jié)果中的第一個元素;然后,對剩余的元素全排列

* @author rico

* @param s

* 字符數(shù)組

* @param from

* 起始下標

* @param to

* 終止下標

*/

public static void getStringPermutations3(char[] s, int from, int to) {

if (s != null && to >= from && to < s.length && from >= 0) { // 邊界條件檢查

if (from == to) { // 遞歸終止條件

System.out.println(s); // 打印結(jié)果

} else {

for (int i = from; i <= to; i++) {

swap(s, i, from); // 交換前綴,作為結(jié)果中的第一個元素,然后對剩余的元素全排列

getStringPermutations3(s, from + 1, to); // 遞歸調(diào)用,縮小問題的規(guī)模

swap(s, from, i); // 換回前綴,復(fù)原字符數(shù)組

}

}

}

}

/**

*@description 對字符數(shù)組中的制定字符進行交換

*@author rico

*@param s

*@param from

*@param to

*/

public static void swap(char[] s, int from, int to) {

char temp = s[from];

s[from] = s[to];

s[to] = temp;

}

非遞歸解法(字典序全排列)

/**

* Title: 字符串全排列非遞歸算法(字典序全排列)

* Description: 字典序全排列,其基本思想是:

* 先對需要求排列的字符串進行字典排序,即得到全排列中最小的排列.

* 然后,找到一個比它大的最小的全排列,一直重復(fù)這一步直到找到最大值,即字典排序的逆序列.

*

* 不需要關(guān)心字符串長度

*

* @author rico

*/

public class StringPermutationsLoop {

/**

* @description 字典序全排列

*

* 設(shè)一個字符串(字符數(shù)組)的全排列有n個,分別是A1,A2,A3,...,An

*

* 1. 找到最小的排列 Ai

* 2. 找到一個比Ai大的最小的后繼排列Ai+1

* 3. 重復(fù)上一步直到?jīng)]有這樣的后繼

*

* 重點就是如何找到一個排列的直接后繼:

* 對于字符串(字符數(shù)組)a0a1a2……an,

* 1. 從an到a0尋找第一次出現(xiàn)的升序排列的兩個字符(即ai < ai+1),那么ai+1是一個極值,因為ai+1之后的字符為降序排列,記 top=i+1;

* 2. 從top處(包括top)開始查找比ai大的最小的值aj,記 minMax = j;

* 3. 交換minMax處和top-1處的字符;

* 4. 翻轉(zhuǎn)top之后的字符(包括top),即得到一個排列的直接后繼排列

*

* @author rico

* @param s

* 字符數(shù)組

* @param from

* 起始下標

* @param to

* 終止下標

*/

public static void getStringPermutations4(char[] s, int from, int to) {

Arrays.sort(s,from,to+1); // 對字符數(shù)組的所有元素進行升序排列,即得到最小排列

System.out.println(s);

char[] descendArr = getMaxPermutation(s, from, to); // 得到最大排列,即最小排列的逆序列

while (!Arrays.equals(s, descendArr)) { // 循環(huán)終止條件:迭代至最大排列

if (s != null && to >= from && to < s.length && from >= 0) { // 邊界條件檢查

int top = getExtremum(s, from, to); // 找到序列的極值

int minMax = getMinMax(s, top, to); // 從top處(包括top)查找比s[top-1]大的最小值所在的位置

swap(s, top - 1, minMax); // 交換minMax處和top-1處的字符

s = reverse(s, top, to); // 翻轉(zhuǎn)top之后的字符

System.out.println(s);

}

}

}

/**

*@description 對字符數(shù)組中的制定字符進行交換

*@author rico

*@param s

*@param from

*@param to

*/

public static void swap(char[] s, int from, int to) {

char temp = s[from];

s[from] = s[to];

s[to] = temp;

}

/**

*@description 獲取序列的極值

*@author rico

*@param s 序列

*@param from 起始下標

*@param to 終止下標

*@return

*/

public static int getExtremum(char[] s, int from, int to) {

int index = 0;

for (int i = to; i > from; i--) {

if (s[i] > s[i - 1]) {

index = i;

break;

}

}

return index;

}

/**

*@description 從top處查找比s[top-1]大的最小值所在的位置

*@author rico

*@created 2017年5月10日 上午9:21:13

*@param s

*@param top 極大值所在位置

*@param to

*@return

*/

public static int getMinMax(char[] s, int top, int to) {

int index = top;

char base = s[top-1];

char temp = s[top];

for (int i = top + 1; i <= to; i++) {

if (s[i] > base && s[i] < temp) {

temp = s[i];

index = i;

}

continue;

}

return index;

}

/**

*@description 翻轉(zhuǎn)top(包括top)后的序列

*@author rico

*@param s

*@param from

*@param to

*@return

*/

public static char[] reverse(char[] s, int top, int to) {

char temp;

while(top < to){

temp = s[top];

s[top] = s[to];

s[to] = temp;

top ++;

to --;

}

return s;

}

/**

*@description 根據(jù)最小排列得到最大排列

*@author rico

*@param s 最小排列

*@param from 起始下標

*@param to 終止下標

*@return

*/

public static char[] getMaxPermutation(char[] s, int from, int to) {

//將最小排列復(fù)制到一個新的數(shù)組中

char[] dsc = Arrays.copyOfRange(s, 0, s.length);

int first = from;

int end = to;

while(end > first){ // 循環(huán)終止條件

char temp = dsc[first];

dsc[first] = dsc[end];

dsc[end] = temp;

first ++;

end --;

}

return dsc;

}

(6). 二分查找

/**

* @description 二分查找的遞歸實現(xiàn)

* @author rico

* @param array 目標數(shù)組

* @param low 左邊界

* @param high 右邊界

* @param target 目標值

* @return 目標值所在位置

*/

public static int binarySearch(int[] array, int low, int high, int target) {

//遞歸終止條件

if(low <= high){

int mid = (low + high) >> 1;

if(array[mid] == target){

return mid + 1; // 返回目標值的位置,從1開始

}else if(array[mid] > target){

// 由于array[mid]不是目標值,因此再次遞歸搜索時,可以將其排除

return binarySearch(array, low, mid-1, target);

}else{

// 由于array[mid]不是目標值,因此再次遞歸搜索時,可以將其排除

return binarySearch(array, mid+1, high, target);

}

}

return -1; //表示沒有搜索到

}

--------------------------------我是分割線-------------------------------------

/**

*@description 二分查找的非遞歸實現(xiàn)

*@author rico

*@param array 目標數(shù)組

*@param low 左邊界

*@param high 右邊界

*@param target 目標值

*@return 目標值所在位置

*/

public static int binarySearchNoRecursive(int[] array, int low, int high, int target) {

// 循環(huán)

while (low <= high) {

int mid = (low + high) >> 1;

if (array[mid] == target) {

return mid + 1; // 返回目標值的位置,從1開始

} else if (array[mid] > target) {

// 由于array[mid]不是目標值,因此再次遞歸搜索時,可以將其排除

high = mid -1;

} else {

// 由于array[mid]不是目標值,因此再次遞歸搜索時,可以將其排除

low = mid + 1;

}

}

return -1; //表示沒有搜索到

}

第二類問題:問題解法按遞歸算法實現(xiàn)

(1). 漢諾塔問題

/**

* Title: 漢諾塔問題

* Description:古代有一個梵塔,塔內(nèi)有三個座A、B、C,A座上有64個盤子,盤子大小不等,大的在下,小的在上。

* 有一個和尚想把這64個盤子從A座移到C座,但每次只能允許移動一個盤子,并且在移動過程中,3個座上的盤子始終保持大盤在下,

* 小盤在上。在移動過程中可以利用B座。要求輸入層數(shù),運算后輸出每步是如何移動的。

*

* @author rico

*/

public class HanoiTower {

/**

*@description 在程序中,我們把最上面的盤子稱為第一個盤子,把最下面的盤子稱為第N個盤子

*@author rico

*@param level:盤子的個數(shù)

*@param from 盤子的初始地址

*@param inter 轉(zhuǎn)移盤子時用于中轉(zhuǎn)

*@param to 盤子的目的地址

*/

public static void moveDish(int level, char from, char inter, char to) {

if (level == 1) { // 遞歸終止條件

System.out.println("從" + from + " 移動盤子" + level + " 號到" + to);

} else {

// 遞歸調(diào)用:將level-1個盤子從from移到inter(不是一次性移動,每次只能移動一個盤子,其中to用于周轉(zhuǎn))

moveDish(level - 1, from, to, inter); // 遞歸調(diào)用,縮小問題的規(guī)模

// 將第level個盤子從A座移到C座

System.out.println("從" + from + " 移動盤子" + level + " 號到" + to);

// 遞歸調(diào)用:將level-1個盤子從inter移到to,from 用于周轉(zhuǎn)

moveDish(level - 1, inter, from, to); // 遞歸調(diào)用,縮小問題的規(guī)模

}

}

public static void main(String[] args) {

int nDisks = 30;

moveDish(nDisks, 'A', 'B', 'C');

}

第三類問題:數(shù)據(jù)的結(jié)構(gòu)是按遞歸定義的

(1). 二叉樹深度

/**

* Title: 遞歸求解二叉樹的深度

* Description:

* @author rico

* @created 2017年5月8日 下午6:34:50

*/

public class BinaryTreeDepth {

/**

*@description 返回二叉數(shù)的深度

*@author rico

*@param t

*@return

*/

public static int getTreeDepth(Tree t) {

// 樹為空

if (t == null) // 遞歸終止條件

return 0;

int left = getTreeDepth(t.left); // 遞歸求左子樹深度,縮小問題的規(guī)模

int right = getTreeDepth(t.left); // 遞歸求右子樹深度,縮小問題的規(guī)模

return left > right ? left + 1 : right + 1;

}

}

(2). 二叉樹深度

/**

* @description 前序遍歷(遞歸)

* @author rico

* @created 2017年5月22日 下午3:06:11

* @param root

* @return

*/

public String preOrder(Node root) {

StringBuilder sb = new StringBuilder(); // 存到遞歸調(diào)用棧

if (root == null) { // 遞歸終止條件

return ""; // ji

}else { // 遞歸終止條件

sb.append(root.data + " "); // 前序遍歷當前結(jié)點

sb.append(preOrder(root.left)); // 前序遍歷左子樹

sb.append(preOrder(root.right)); // 前序遍歷右子樹

return sb.toString();

}

}

總結(jié)

以上是生活随笔為你收集整理的java break递归_【Java】递归总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。