container 包詳解

Go 語言中有一個 container 包,如果只是看這個包名,可能很容易讓人誤解,但這個 container 和 Docker 之類的容器沒有關(guān)系。

在 container 包中,有三種開箱即用的數(shù)據(jù)結(jié)構(gòu),可以直接使用,分別是 heap、list 和 ring。

heap

heap 中提供了一個的實現(xiàn),可以直接使用。如果想創(chuàng)建一個堆,只需要先實現(xiàn)一些方法,這里以整數(shù)堆為例:

type IntHeap []int

func (h IntHeap) Len() int           { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *IntHeap) Push(x interface{}) {
    *h = append(*h, x.(int))
}

func (h *IntHeap) Pop() interface{} {
    old := *h
    n := len(old)
    x := old[n-1]
    *h = old[0 : n-1]
    return x
}

在上面的實現(xiàn)中,沒有對堆的實現(xiàn),因為 heap 包已經(jīng)把這些實現(xiàn)抽象出來了,在使用的時候,只需要自己實現(xiàn)堆中數(shù)據(jù)比較大小的邏輯。上面的代碼寫完之后,就可以來初始化并使用堆:

h := &IntHeap{2, 1, 5}
heap.Init(h) // 初始化堆

heap.Push(h, 3) // 入堆
heap.Pop(h) // 出堆,拿出堆頂?shù)牡谝粋€元素

在 Go 的官方文檔中,甚至使用 heap 包實現(xiàn)了一個優(yōu)先級隊列,如果在業(yè)務(wù)場景中有這個需求,都可以直接使用了。具體見:https://golang.google.cn/pkg/container/heap/

list

list 是一個雙向鏈表的實現(xiàn),這個數(shù)據(jù)結(jié)構(gòu)的使用就更簡單了,開箱即用:

l := list.New()  // 創(chuàng)建一個雙向鏈表
e4 := l.PushBack(4) // 從后面加入元素
e1 := l.PushFront(1) // 從前面加入元素
l.InsertBefore(3, e4) // 在某個元素之前插入
l.InsertAfter(2, e1) // 在某個元素之后插入

// 按照鏈表的順序,從前向后遍歷
for e := l.Front(); e != nil; e = e.Next() {
      fmt.Println(e.Value)
}

ring

ring 這個數(shù)據(jù)結(jié)構(gòu)有點特殊,是一個環(huán)狀的雙向鏈表,這個數(shù)據(jù)結(jié)構(gòu)在有些場景下很有用,比如用作任務(wù)隊列。

這個結(jié)構(gòu)有個好處是內(nèi)存在初始化的時候申請一次就可以了,其中的內(nèi)存式可以重復利用了。

使用起來也比較方便,可以使用 Next 和 Prev 方法去獲取前面和后面的元素:

r := ring.New(5) // 創(chuàng)建一個大小為 5 的ring

n := r.Len() // 獲取 ring 的長度

// 向 ring 中填充數(shù)據(jù)
for i := 0; i < n; i++ {
    r.Value = i
    r = r.Next()
}

// 打印 ring 中的數(shù)據(jù)
r.Do(func(p interface{}) {
    fmt.Println(p.(int))
})

ring 中還提供了兩個特殊的方法:Link 和 UnLink。

Link 方法可以把兩個 ring 連接起來:

r := ring.New(2)
s := ring.New(2)

lr := r.Len()
ls := s.Len()

for i := 0; i < lr; i++ {
    r.Value = 0
    r = r.Next()
}

for j := 0; j < ls; j++ {
    s.Value = 1
    s = s.Next()
}

rs := r.Link(s)

rs.Do(func(p interface{}) {
    fmt.Println(p.(int))
})

UnLink 方法是從 ring 摘除調(diào)一些節(jié)點,Unlink 的參數(shù)是整數(shù) n ,表示從 r.Next 開始,摘除三個元素:

r := ring.New(6)

n := r.Len()

for i := 0; i < n; i++ {
    r.Value = i
    r = r.Next()
}

r.Unlink(3)

r.Do(func(p interface{}) {
    fmt.Println(p.(int))
})

文 / Rayjun

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容