
Java 教程
- Java - 首頁
- Java - 概述
- Java - 歷史
- Java - 特性
- Java 與 C++
- JVM - Java 虛擬機器
- Java - JDK 與 JRE 與 JVM
- Java - Hello World 程式
- Java - 環境搭建
- Java - 基本語法
- Java - 變數型別
- Java - 資料型別
- Java - 型別轉換
- Java - Unicode 系統
- Java - 基本運算子
- Java - 註釋
- Java - 使用者輸入
- Java - 日期和時間
Java 控制語句
- Java - 迴圈控制
- Java - 決策制定
- Java - if-else
- Java - switch
- Java - for 迴圈
- Java - for-each 迴圈
- Java - while 迴圈
- Java - do-while 迴圈
- Java - break
- Java - continue
面向物件程式設計
- Java - 面向物件概念
- Java - 物件和類
- Java - 類屬性
- Java - 類方法
- Java - 方法
- Java - 變數作用域
- Java - 建構函式
- Java - 訪問修飾符
- Java - 繼承
- Java - 聚合
- Java - 多型
- Java - 方法覆蓋
- Java - 方法過載
- Java - 動態繫結
- Java - 靜態繫結
- Java - 例項初始化塊
- Java - 抽象
- Java - 封裝
- Java - 介面
- Java - 包
- Java - 內部類
- Java - 靜態類
- Java - 匿名類
- Java - 單例類
- Java - 包裝類
- Java - 列舉
- Java - 列舉建構函式
- Java - 列舉字串
Java 內建類
Java 檔案處理
Java 錯誤和異常
- Java - 異常
- Java - try-catch 塊
- Java - try-with-resources
- Java - 多重 catch 塊
- Java - 巢狀 try 塊
- Java - finally 塊
- Java - throw 異常
- Java - 異常傳播
- Java - 內建異常
- Java - 自定義異常
Java 多執行緒
- Java - 多執行緒
- Java - 執行緒生命週期
- Java - 建立執行緒
- Java - 啟動執行緒
- Java - 執行緒連線
- Java - 執行緒命名
- Java - 執行緒排程器
- Java - 執行緒池
- Java - 主執行緒
- Java - 執行緒優先順序
- Java - 守護執行緒
- Java - 執行緒組
- Java - 關閉鉤子
Java 同步
Java 網路程式設計
- Java - 網路程式設計
- Java - 套接字程式設計
- Java - URL 處理
- Java - URL 類
- Java - URLConnection 類
- Java - HttpURLConnection 類
- Java - Socket 類
- Java -泛型
Java 集合
Java 介面
Java 資料結構
Java 集合演算法
高階 Java
- Java - 命令列引數
- Java - Lambda 表示式
- Java - 傳送郵件
- Java - Applet 基礎
- Java - Javadoc 註釋
- Java - 自動裝箱和拆箱
- Java - 檔案不匹配方法
- Java - REPL (JShell)
- Java - 多版本 Jar 檔案
- Java - 私有介面方法
- Java - 內部類菱形運算子
- Java - 多解析度影像 API
- Java - 集合工廠方法
- Java - 模組系統
- Java - Nashorn JavaScript
- Java - Optional 類
- Java - 方法引用
- Java - 函式式介面
- Java - 預設方法
- Java - Base64 編碼解碼
- Java - switch 表示式
- Java - Teeing 收集器
- Java - 微基準測試
- Java - 文字塊
- Java - 動態 CDS 歸檔
- Java - Z 垃圾收集器 (ZGC)
- Java - 空指標異常
- Java - 打包工具
- Java - 密封類
- Java - 記錄類
- Java - 隱藏類
- Java - 模式匹配
- Java - 簡潔的數字格式化
- Java - 垃圾回收
- Java - JIT 編譯器
Java 雜項
- Java - 遞迴
- Java - 正則表示式
- Java - 序列化
- Java - 字串
- Java - Process API改進
- Java - Stream API改進
- Java - 增強的 @Deprecated 註解
- Java - CompletableFuture API改進
- Java - 流
- Java - 日期時間 API
- Java 8 - 新特性
- Java 9 - 新特性
- Java 10 - 新特性
- Java 11 - 新特性
- Java 12 - 新特性
- Java 13 - 新特性
- Java 14 - 新特性
- Java 15 - 新特性
- Java 16 - 新特性
Java API 和框架
Java 類引用
- Java - Scanner
- Java - 陣列
- Java - 字串
- Java - Date
- Java - ArrayList
- Java - Vector
- Java - Stack
- Java - PriorityQueue
- Java - LinkedList
- Java - ArrayDeque
- Java - HashMap
- Java - LinkedHashMap
- Java - WeakHashMap
- Java - EnumMap
- Java - TreeMap
- Java - IdentityHashMap
- Java - HashSet
- Java - EnumSet
- Java - LinkedHashSet
- Java - TreeSet
- Java - BitSet
- Java - Dictionary
- Java - Hashtable
- Java - Properties
- Java - Collection
- Java - Array
Java 有用資源
Java - 遞迴
Java - 遞迴
遞迴是一種程式設計技術,其中一個方法根據需要呼叫自身以執行子操作。呼叫自身的那個方法被稱為遞迴函式。遞迴主要用於將大型問題分解成較小的問題,然後遞迴地解決它們。遞迴技術使程式碼更易讀和更具表達力。
示例
考慮以下情況:
// recursive method public int sum(int n){ // recursive method call return n == 1 ? 1 : n + sum(n-1); }
在這種情況下,我們使用遞迴來獲取n個自然數的和,它可以表示為n + n-1個數的和。使用遞迴,我們將n-1個自然數的和的結果與n相加以獲得所需的結果。
由於遞迴函式會呼叫自身,因此必須存在一個基準條件,根據該條件,遞迴方法可以停止無限地呼叫自身。如果基準條件不存在或永遠不會為真,則它會在程式中導致堆疊溢位。在上面的示例中,我們的基準條件是n為1。
public int sum(int n){ // base condition if(n == 1){ return 1; } // recursive call return n + sum(n-1); }
如果我們用負整數呼叫此函式,則會導致堆疊溢位錯誤。
Java 中的遞迴是如何工作的?
在 Java 中,變數、方法呼叫、引用儲存在堆疊中,而物件則在堆中分配記憶體。每當呼叫一個方法時,它的詳細資訊都會被壓入堆疊,例如傳遞的引數的值、任何區域性變數、計算等等。在遞迴呼叫期間,每當一個方法呼叫自身時,它的條目就會被壓入堆疊,直到基準條件終止流程。當基準條件為真時,並且方法開始返回值時,子呼叫的結果會從堆疊中彈出,依此類推,直到方法的所有條目都從堆疊中彈出。讓我們用一個例子來理解這一點。
示例
package com.tutorialspoint; public class Tester { public static void main(String[] args) { Tester tester = new Tester(); int result = tester.sum(5); System.out.println("Sum: " + result); } public int sum(int n){ System.out.println("Input: " + n); int result; // base condition if(n == 1){ result = 1; System.out.println("Base condition fulfilled."); }else { // recursive call result = n + sum(n-1); } System.out.println("Result: " + result); return result; } }
輸出
讓我們編譯並執行上述程式,這將產生以下結果:
Input: 5 Input: 4 Input: 3 Input: 2 Input: 1 Base condition fulfilled. Result: 1 Result: 3 Result: 6 Result: 10 Result: 15 Sum: 15
在這個程式中,我們可以很容易地看到,在遞迴呼叫期間,最初的輸入值會一直列印到滿足基準條件為止,因為方法呼叫正在被壓入堆疊。一旦滿足基準條件,遞迴呼叫就完成了,方法的結果從堆疊中彈出,這從輸出中可以明顯看出。
Java 遞迴示例
1. 使用遞迴計算階乘
階乘是一個數學表示式,它表示以下公式。
n! = n * (n-1)!
這類問題非常適合使用遞迴來解決。考慮以下程式碼片段。
fact(n) = n * fact(n-1)
這裡有一個 fact() 方法,它將返回給定自然數的階乘。現在在實現 fact() 之前,我們應該很好地考慮基準條件,基準條件如下。
1! = 1
現在讓我們看看使用遞迴計算階乘的完整示例。
package com.tutorialspoint; public class Tester { public static void main(String[] args) { Tester tester = new Tester(); // call the recursive method to get the factorial int result = tester.fact(5); System.out.println("Factorial: " + result); } // recursive method public int fact(int n) { // if base condition is not true, make a recursive call return n == 1 ? 1: n * fact(n-1); } }
輸出
讓我們編譯並執行上述程式,這將產生以下結果:
Factorial: 120
2. 使用遞迴計算斐波那契數列的和
斐波那契數列是數學中一個非常重要且有趣的數列。它表示以下等式:
F(n) = F(n-1) + F(n-2)
在這裡,我們可以說,斐波那契數表示其前一個數和次前一個數的和。斐波那契數列的形式是 0, 1, 1, 2, 3, 5 等等。
使用遞迴,我們可以很容易地計算斐波那契數。考慮以下程式碼片段。
fibo(n) = fibo(n-1) + fibo(n-2)
這裡有一個 fibo() 方法,它將返回給定整數的斐波那契數。現在在實現 fibo() 之前,我們應該很好地考慮基準條件,基準條件如下。
fibo(0) = 0; fibo(1) = 1;
現在讓我們看看使用遞迴計算斐波那契數的完整示例。
package com.tutorialspoint; public class Tester { public static void main(String[] args) { Tester tester = new Tester(); int result = tester.fibo(5); System.out.println("Fibbonacci: " + result); } public int fibo(int n) { return n <= 1 ? n : fibo(n-1) + fibo(n-2); } }
輸出
讓我們編譯並執行上述程式,這將產生以下結果:
Fibbonacci: 5
在 Java 中使用遞迴的優點
以下是 Java 中使用遞迴的優點:
- 更簡潔的程式碼 使用遞迴使程式碼易於理解並保持程式碼簡潔。與其使用多個 if 和迴圈條件,遞迴有助於以函式式方式編寫程式碼。
- 遞迴演算法 對於某些問題,例如樹遍歷、漢諾塔問題等,遞迴是編碼解決方案的最佳方法。
- 減少時間複雜度 遞迴程式有助於減少在大型資料集上搜索所需的時間。
在 Java 中使用遞迴的缺點
以下是 Java 中使用遞迴的缺點:
- 專業知識 儘管遞迴是一種更簡潔的方法,但它需要高度的專業知識和對問題陳述和擬議解決方案的理解。不正確地實現遞迴可能會導致效能問題,並且可能難以除錯。
- 記憶體空間密集 由於涉及多個函式呼叫和返回流,遞迴程式通常是記憶體密集型的。