Like Share Discussion Bookmark Smile

J.J. Huang   2025-03-08   Getting Started Golang 04.函式   瀏覽次數:次   DMCA.com Protection Status

Go | 了解「遞迴函式」應用

💬 簡介

遞迴是程式設計中的一種重要技術,指的是一個函式在其執行過程中呼叫自己。Go 語言作為一種功能強大的程式語言,同樣支持遞迴的應用,讓開發者能夠以簡潔且高效的方式解決一些複雜的問題。

本文將介紹 Go 語言中的遞迴函式,並展示如何通過遞迴解決常見的問題,例如計算階乘、處理樹狀結構等。

圖片來源:Gophers


🔎 遞迴函式基礎

1️⃣ 什麼是遞迴?

遞迴是指一個函式在它的內部呼叫自己。在遞迴中,通常會設置一個基礎條件,當達到這個條件時,遞迴停止並返回結果。否則,遞迴會繼續進行,直到達到基礎條件。

2️⃣ 遞迴的基本結構

在遞迴函式中,通常有兩個部分:

  • 基礎條件:當達到此條件時,遞迴停止。
  • 遞迴步驟:函式呼叫自己來解決子問題。

3️⃣ 基本範例:計算階乘

階乘(Factorial)是遞迴的一個經典範例。階乘的定義是:

  • n! = n * (n-1)!,其中 0! = 1

  • 範例:計算階乘

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package main

    import "fmt"

    // 計算階乘的遞迴函式
    func factorial(n int) int {
    if n == 0 {
    return 1 // 基礎條件
    }
    return n * factorial(n-1) // 遞迴步驟
    }

    func main() {
    fmt.Println("5! =", factorial(5)) // 5! = 120
    }

    輸出結果:

    1
    5! = 120

    📝 在這個範例中,factorial 函式會不斷呼叫自己,直到 n 等於 0,並返回最終的階乘結果。

4️⃣ 遞迴的思考過程

當使用遞迴解決問題時,通常需要考慮兩個方面:

  • 基礎條件:必須確保遞迴能夠終止,否則會導致無限遞迴。
  • 遞迴步驟:每次遞迴呼叫必須處理一個比前一次更簡單的子問題,並逐漸逼近基礎條件。

🚀 應用場景

1️⃣ 處理樹狀結構

遞迴在處理樹狀結構(如文件系統、組織結構等)時非常有用。每個節點可以有多個子節點,遞迴可以讓我們方便地遍歷整個樹。

  • 範例:遍歷樹狀結構
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package main

    import "fmt"

    // 定義樹節點結構
    type TreeNode struct {
    Value int
    Left *TreeNode
    Right *TreeNode
    }

    // 遞迴遍歷樹的函式
    func inorderTraversal(node *TreeNode) {
    if node != nil {
    inorderTraversal(node.Left) // 遞迴遍歷左子樹
    fmt.Println(node.Value) // 輸出節點值
    inorderTraversal(node.Right) // 遞迴遍歷右子樹
    }
    }

    func main() {
    root := &TreeNode{Value: 1}
    root.Left = &TreeNode{Value: 2}
    root.Right = &TreeNode{Value: 3}
    root.Left.Left = &TreeNode{Value: 4}
    root.Left.Right = &TreeNode{Value: 5}

    inorderTraversal(root) // 輸出: 4 2 5 1 3
    }
    輸出結果:
    1
    2
    3
    4
    5
    4
    2
    5
    1
    3

    📝 在這個範例中,inorderTraversal 函式遞迴地遍歷整個二叉樹,並按照中序遍歷的順序輸出每個節點的值。

2️⃣ 解決分治問題

分治策略通常依賴遞迴來將一個大問題分解為多個小問題,並逐一解決它們。經典的分治演算法包括快速排序和合併排序。

  • 範例:快速排序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package main

    import "fmt"

    // 快速排序函式
    func quickSort(arr []int) []int {
    if len(arr) < 2 {
    return arr // 基礎條件,當陣列長度小於 2 時不再遞迴
    }
    pivot := arr[0]
    left := []int{}
    right := []int{}

    for _, v := range arr[1:] {
    if v < pivot {
    left = append(left, v)
    } else {
    right = append(right, v)
    }
    }

    left = quickSort(left) // 遞迴處理左邊子陣列
    right = quickSort(right) // 遞迴處理右邊子陣列

    return append(append(left, pivot), right...)
    }

    func main() {
    arr := []int{9, 7, 5, 11, 12, 2, 14, 3, 10, 6}
    fmt.Println("排序結果:", quickSort(arr))
    }
    輸出結果:
    1
    排序結果: [2 3 5 6 7 9 10 11 12 14]

    📝 這個範例展示了快速排序演算法,其中遞迴的過程將陣列分割成兩部分,分別排序後合併結果。

3️⃣ 計算斐波那契數列

斐波那契數列是另一個常見的遞迴問題,其中每一項都是前兩項的和。這個問題可以通過遞迴來簡單實現。

  • 範例:計算斐波那契數列
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package main

    import "fmt"

    // 計算斐波那契數列的遞迴函式
    func fibonacci(n int) int {
    if n <= 1 {
    return n // 基礎條件
    }
    return fibonacci(n-1) + fibonacci(n-2) // 遞迴步驟
    }

    func main() {
    for i := 0; i < 10; i++ {
    fmt.Printf("%d ", fibonacci(i))
    }
    }
    輸出結果:
    1
    0 1 1 2 3 5 8 13 21 34

    📝 這個範例展示了如何使用遞迴計算斐波那契數列中的每一項。


⚠️ 注意事項

📌 遞迴的效能問題

雖然遞迴能夠簡潔地解決許多問題,但過多的遞迴呼叫可能會導致堆疊溢位。特別是在處理大規模資料或深度遞迴時,必須小心使用。

📌 疊代 vs 遞迴

有些問題可以用疊代(loop)來解決,這樣能夠避免遞迴可能帶來的性能問題。在某些情況下,疊代方式可能更高效。


🎯 總結

  • 遞迴是一種強大的程式設計技術,能夠幫助開發者簡潔地解決各類問題。
  • Go 語言支援遞迴函式,可以用於計算階乘、處理樹狀結構、分治演算法等多種場景。
  • 在使用遞迴時要小心處理基礎條件和遞迴步驟,避免無限遞迴或堆疊溢位。

掌握遞迴的基本概念和應用,能夠讓你的程式設計變得更加靈活且高效。

最後建議回顧一下 Go | 菜鳥教學 目錄,了解其章節內容。


註:以上參考了
Go