掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
列表是一種非連續(xù)的存儲容器,由多個節(jié)點組成,節(jié)點通過一些變量記錄彼此之間的關(guān)系,列表有多種實現(xiàn)方法,如單鏈表、雙鏈表等。

列表的原理可以這樣理解:假設(shè) A、B、C 三個人都有電話號碼,如果 A 把號碼告訴給 B,B 把號碼告訴給 C,這個過程就建立了一個單鏈表結(jié)構(gòu),如下圖所示。
圖:三人單向通知電話號碼形成單鏈表結(jié)構(gòu)
如果在這個基礎(chǔ)上,再從 C 開始將自己的號碼告訴給自己所知道號碼的主人,這樣就形成了雙鏈表結(jié)構(gòu),如下圖所示。
圖:三人相互通知電話號碼形成雙鏈表結(jié)構(gòu)
那么如果需要獲得所有人的號碼,只需要從 A 或者 C 開始,要求他們將自己的號碼發(fā)出來,然后再通知下一個人如此循環(huán),這樣就構(gòu)成了一個列表遍歷的過程。
如果 B 換號碼了,他需要通知 A 和 C,將自己的號碼移除,這個過程就是列表元素的刪除操作,如下圖所示。
圖:從雙鏈表中刪除一人的電話號碼
在Go語言中,列表使用 container/list 包來實現(xiàn),內(nèi)部的實現(xiàn)原理是雙鏈表,列表能夠高效地進行任意位置的元素插入和刪除操作。
list 的初始化有兩種方法:分別是使用 New() 函數(shù)和 var 關(guān)鍵字聲明,兩種方法的初始化效果都是一致的。
1) 通過 container/list 包的 New() 函數(shù)初始化 list
變量名 := list.New()
2) 通過 var 關(guān)鍵字聲明初始化 list
var 變量名 list.List
列表與切片和 map 不同的是,列表并沒有具體元素類型的限制,因此,列表的元素可以是任意類型,這既帶來了便利,也引來一些問題,例如給列表中放入了一個 interface{} 類型的值,取出值后,如果要將 interface{} 轉(zhuǎn)換為其他類型將會發(fā)生宕機。
雙鏈表支持從隊列前方或后方插入元素,分別對應(yīng)的方法是 PushFront 和 PushBack。
這兩個方法都會返回一個 *list.Element 結(jié)構(gòu),如果在以后的使用中需要刪除插入的元素,則只能通過 *list.Element 配合 Remove() 方法進行刪除,這種方法可以讓刪除更加效率化,同時也是雙鏈表特性之一。
下面代碼展示如何給 list 添加元素:
l := list.New()
l.PushBack("fist")
l.PushFront(67)代碼說明如下:
列表插入元素的方法如下表所示。
| 方 法 | 功 能 |
|---|---|
| InsertAfter(v interface {}, mark * Element) * Element | 在 mark 點之后插入元素,mark 點由其他插入函數(shù)提供 |
| InsertBefore(v interface {}, mark * Element) *Element | 在 mark 點之前插入元素,mark 點由其他插入函數(shù)提供 |
| PushBackList(other *List) | 添加 other 列表元素到尾部 |
| PushFrontList(other *List) | 添加 other 列表元素到頭部 |
列表插入函數(shù)的返回值會提供一個 *list.Element 結(jié)構(gòu),這個結(jié)構(gòu)記錄著列表元素的值以及與其他節(jié)點之間的關(guān)系等信息,從列表中刪除元素時,需要用到這個結(jié)構(gòu)進行快速刪除。
列表操作元素:
package main
import "container/list"
func main() {
l := list.New()
// 尾部添加
l.PushBack("canon")
// 頭部添加
l.PushFront(67)
// 尾部添加后保存元素句柄
element := l.PushBack("fist")
// 在fist之后添加high
l.InsertAfter("high", element)
// 在fist之前添加noon
l.InsertBefore("noon", element)
// 使用
l.Remove(element)
} 代碼說明如下:
第 6 行,創(chuàng)建列表實例。
第 9 行,將字符串 canon 插入到列表的尾部。
第 12 行,將數(shù)值 67 添加到列表的頭部。
第 15 行,將字符串 fist 插入到列表的尾部,并將這個元素的內(nèi)部結(jié)構(gòu)保存到 element 變量中。
第 18 行,使用 element 變量,在 element 的位置后面插入 high 字符串。
第 21 行,使用 element 變量,在 element 的位置前面插入 noon 字符串。
第 24 行,移除 element 變量對應(yīng)的元素。
下表中展示了每次操作后列表的實際元素情況。
| 操作內(nèi)容 | 列表元素 |
|---|---|
| l.PushBack("canon") | canon |
| l.PushFront(67) | 67, canon |
| element := l.PushBack("fist") | 67, canon, fist |
| l.InsertAfter("high", element) | 67, canon, fist, high |
| l.InsertBefore("noon", element) | 67, canon, noon, fist, high |
| l.Remove(element) | 67, canon, noon, high |
遍歷雙鏈表需要配合 Front() 函數(shù)獲取頭元素,遍歷時只要元素不為空就可以繼續(xù)進行,每一次遍歷都會調(diào)用元素的 Next() 函數(shù),代碼如下所示。
l := list.New()
// 尾部添加
l.PushBack("canon")
// 頭部添加
l.PushFront(67)
for i := l.Front(); i != nil; i = i.Next() {
fmt.Println(i.Value)
}代碼輸出如下:
67
canon
代碼說明如下:

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流