Go語言源碼閱讀(4) - container/list | 鏈表

歡迎訪問我的個(gè)人網(wǎng)站獲取更佳閱讀排版:Go語言源碼閱讀(4) - container/list | 鏈表 | yoko blog (https://pengrl.com/p/51973/)

是雙向鏈表。

實(shí)現(xiàn)上,有哨兵root節(jié)點(diǎn),即當(dāng)鏈表為空時(shí),還有一個(gè)哨兵元素。

實(shí)現(xiàn)多態(tài)的方式是Element結(jié)構(gòu)體內(nèi)有一個(gè)interface{}數(shù)據(jù)成員,可以用來存儲(chǔ)任意類型的數(shù)據(jù)。其余鏈表和鏈表元素的代碼都是系統(tǒng)庫(kù)提供的。

container/list/example_test.go演示了如何申請(qǐng)一個(gè)List,并對(duì)它進(jìn)行一些插入操作后,如何遍歷訪問該List。

有一點(diǎn)非常值得思考,就是Go語言沒有構(gòu)造函數(shù),從而導(dǎo)致的一些問題。
當(dāng)一個(gè)結(jié)構(gòu)體變量在使用前需要對(duì)它的數(shù)據(jù)成員做一些非zero out的初始化時(shí)(Go語言會(huì)對(duì)所有數(shù)據(jù)成員做zero out),
要么是提供一個(gè)New接口,接口返回一個(gè)結(jié)構(gòu)體的指針類型,內(nèi)部實(shí)現(xiàn)是實(shí)例化結(jié)構(gòu)體變量后,然后做Init操作。但是從語意上來講,這種變量是分配在堆上的。
要么是提供一個(gè)Init接口,壞處是要么用戶在棧上聲明了結(jié)構(gòu)體變量時(shí),還需要手動(dòng)調(diào)用Init函數(shù),增加了使用時(shí)成本。要么是在其他的方法內(nèi)部做lazy init,這又增加了結(jié)構(gòu)體的實(shí)現(xiàn)復(fù)雜度,以及小小的性能(畢竟lazy init每次都要判斷是否已經(jīng)init了)。

List提供的對(duì)外接口有:

常規(guī)操作:

// 初始化List,這個(gè)接口并不是在使用List前非調(diào)用不可的,因?yàn)椴糠諰ist的操作會(huì)在操作前判斷List是否已經(jīng)Init并做懶初始化
// 如果先清空一個(gè)List,也可以對(duì)List調(diào)用Init方法
func (l *List) Init() *List

// 返回一個(gè)*List變量
func New() *List

// 獲取List的長(zhǎng)度
// List中會(huì)持續(xù)記錄更新數(shù)據(jù)成員len,所以獲取長(zhǎng)度的復(fù)雜度是`O(1)`的。
func (l *List) Len() int

// 獲取頭部元素
func (l *List) Front() *Element

// 獲取尾部元素
func (l *List) Back() *Element

// 頭部插入
func (l *List) PushFront(v interface{}) *Element

// 尾部插入
func (l *List) PushBack(v interface{}) *Element

// 某個(gè)元素前插入
func (l *List) InsertBefore(v interface{}, mark *Element) *Element

// 某個(gè)元素后插入
func (l *List) InsertAfter(v interface{}, mark *Element) *Element

// 刪除某個(gè)元素
func (l *List) Remove(e *Element) interface{}

wrap類型的操作,對(duì)常規(guī)操作做的組合封裝:

// 將某個(gè)元素移動(dòng)到頭部
func (l *List) MoveToFront(e *Element)

// 將某個(gè)元素移動(dòng)到尾部
func (l *List) MoveToBack(e *Element)

// 將某個(gè)元素<e>移動(dòng)到另一個(gè)元素<mark>的前面,注意,只是移動(dòng)e,不移動(dòng)mark
func (l *List) MoveBefore(e, mark *Element)

// 將某個(gè)元素移動(dòng)到另一個(gè)元素的后面
func (l *List) MoveAfter(e, mark *Element)

最后,還支持鏈表的拼接操作:

// 將<other>鏈表插入<l>鏈表之后
func (l *List) PushBackList(other *List)

// 插到前面
func (l *List) PushFrontList(other *List)

Element提供的接口:

// 可訪問的數(shù)據(jù)成員,可強(qiáng)轉(zhuǎn)成用戶存入的類型
Value interface{}

// 前一個(gè)元素
func (e *Element) Prev() *Element

// 后一個(gè)元素
func (e *Element) Next() *Element

基于Go 1.11.4

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

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

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