
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