Like Share Discussion Bookmark Smile

J.J. Huang   2025-02-19   Getting Started Golang 02.資料結構   瀏覽次數:次   DMCA.com Protection Status

Go | 初步了解「列表」型別

💬 簡介

在程式設計中,「列表」型別是一個非常常用的資料結構,它可以幫助我們儲存和管理一組有序的資料。在 Go 語言中,我們常用兩種資料結構來實現列表:切片(slice)雙向鏈結串列(container/list)。這兩者各有優缺點,適用於不同的情境。

本文將介紹 Go 中的列表型別,並深入探討切片和雙向鏈結串列的差異及使用場景。

圖片來源:Gophers(地鼠造型的原創者為 Renee French)


✨ 切片:Go 語言中的靈活列表

切片(slice) 是 Go 語言中一種非常靈活的資料結構。與陣列不同,切片可以動態增長和縮小。它不僅是對陣列的一層封裝,更具彈性,特別適用於動態大小的資料處理。

1️⃣ 宣告與初始化切片

我們可以用 [] 宣告切片,並使用 append 函式動態地添加元素。

  • 範例:創建與初始化切片
    1
    2
    3
    4
    5
    6
    7
    8
    9
    package main

    import "fmt"

    func main() {
    var numbers []int
    numbers = append(numbers, 1, 2, 3)
    fmt.Println(numbers) // 輸出: [1 2 3]
    }

    📝 在這個範例中,我們創建了一個空的切片並使用 append 向切片中添加元素。

2️⃣ 訪問切片的元素

與陣列類似,可以使用索引來訪問切片的元素。

  • 範例:訪問切片元素
    1
    2
    3
    4
    5
    6
    7
    8
    package main

    import "fmt"

    func main() {
    numbers := []int{1, 2, 3, 4}
    fmt.Println(numbers[2]) // 輸出: 3
    }

    📝 這個範例中,我們通過索引訪問了切片中的第三個元素。

3️⃣ 切片的增長與調整

切片可以隨著需要自動增長,並且提供了多種靈活的操作方法。

  • 範例:調整切片大小
    1
    2
    3
    4
    5
    6
    7
    8
    9
    package main

    import "fmt"

    func main() {
    numbers := []int{1, 2, 3, 4, 5}
    numbers = append(numbers, 6) // 添加元素
    fmt.Println(numbers) // 輸出: [1 2 3 4 5 6]
    }

    📝 在這個範例中,我們使用 append 函式將元素添加到切片的末尾,切片會自動擴展。


🔄 列表的其他實現:container/list

除了使用切片來實現列表,Go 還提供了一個名為 container/list 的標準庫包,實現了雙向鏈結串列。雙向鏈結串列的最大優勢在於其插入與刪除元素的操作非常高效,特別是當元素需要經常被插入或刪除時。

1️⃣ 使用 container/list 創建雙向鏈結串列

首先,必須引入 container/list 包,並使用它來創建一個雙向鏈結串列。

  • 範例:初始化一個空的鏈結串列
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package main

    import (
    "container/list"
    "fmt"
    )

    func main() {
    // 創建一個空的雙向鏈結串列
    l := list.New()

    // 向鏈結串列中添加元素
    l.PushBack(1) // 在末尾插入
    l.PushFront(2) // 在開頭插入

    // 遍歷並輸出鏈結串列中的元素
    for e := l.Front(); e != nil; e = e.Next() {
    fmt.Println(e.Value)
    }
    }

    📝 在這個範例中,我們使用 PushBack 向串列尾部插入元素,並使用 PushFront 向串列頭部插入元素。最後通過 l.Front() 遍歷鏈結串列中的元素。

2️⃣ 插入與刪除操作

與切片相比,container/list 使得插入與刪除元素變得更加高效,特別是在中間插入或刪除元素時。

  • 範例:在中間插入元素
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    package main

    import (
    "container/list"
    "fmt"
    )

    func main() {
    // 初始化鏈結串列
    l := list.New()

    // 添加元素
    e1 := l.PushBack(1)
    e2 := l.PushBack(2)

    // 在中間插入元素
    l.InsertBefore(3, e2) // 在 e2 前插入 3
    l.InsertAfter(4, e1) // 在 e1 後插入 4

    // 輸出結果
    for e := l.Front(); e != nil; e = e.Next() {
    fmt.Println(e.Value)
    }
    }

    📝 在這個範例中,我們使用 InsertBeforeInsertAfter 在特定位置插入元素,這些操作比在切片中間進行插入操作更加高效。


🚀 切片與 container/list 的比較

切片(Slice)

  • 優勢:
    • 查詢速度非常快,適合隨機存取元素。
    • 記憶體空間連續,處理大量資料時更為高效。
    • 靈活,可以動態增減元素。
  • 限制:
    • 插入或刪除中間元素的效率較低,因為必須調整切片中元素的位置。

雙向鏈結串列(container/list

  • 優勢:
    • 插入和刪除元素的操作非常高效,特別是對中間元素的操作。
    • 更適合頻繁增刪元素的場景。
  • 限制:
    • 查詢速度較慢,必須遍歷串列中的每個元素。
    • 記憶體佔用較高,因為每個元素需要存儲指向前後元素的指標。

何時選擇使用

  • 如果你的應用需要頻繁操作(插入、刪除)中間元素,則 container/list 是更好的選擇。
  • 如果你的應用需要高效的隨機訪問並且較少進行插入或刪除操作,那麼切片將是更理想的選擇。

🎯總結

切片和雙向鏈結串列(container/list)是 Go 中常用的兩種列表實現方式,各自有其優勢和限制。理解它們的特性和使用場景,能幫助你更好地選擇最適合你的應用需求的資料結構。

在實際開發中,選擇哪種資料結構取決於操作的需求:如果你需要頻繁進行插入或刪除操作,container/list 是個不錯的選擇;如果你主要需要處理動態資料並且訪問速度至關重要,則切片更為合適。

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


註:以上參考了
Go
Go-container/list