Golang标准库学习—container/list

container包中有三个数据结构:heap(堆)、list(链表)、ring(环)

Package list

import "container/list"

list包实现了双向链表,要遍历一个链表:

for e := l.Front(); e != nil; e = e.Next() {
	// do something with e.Value
}

type Element

Element代表的是链表节点

type Element struct {
	next, prev *Element    // next, prev 分别指向下一个和上一个节点
	list *List             // list 为元素所在链表
	Value interface{}      // Value 为链表节点存储元素
}

Next和Prev方法

// Next 返回链表下一个元素或nil
func (e *Element) Next() *Element {
	if p := e.next; e.list != nil && p != &e.list.root {
		return p
	}
	return nil
}

// Prev 返回链表上一个元素或nil
func (e *Element) Prev() *Element {
	if p := e.prev; e.list != nil && p != &e.list.root {
		return p
	}
	return nil
}

type List

List代表一个双向链表。List零值为一个空的、可用的链表。

type List struct {
	root Element // root 作为哨兵节点
	len  int     // len 是List长度,包括root
}

List有三个基础方法

// 返回一个初始化链表
func New() *List {
	return new(List).Init()
}

// 清空链表
func (l *List) Init() *List {
	l.root.next = &l.root
	l.root.prev = &l.root
	l.len = 0
	return l
}

// 返回链表长度
func (l *List) Len() int {
	return l.len 
}

list中包含的方法包括:

链表功能的基本实现

//延迟初始化
func (l *List) lazyInit() {
	if l.root.next == nil {
		l.Init()
	}
}
//返回list头节点元素
func (l *List) Front() *Element {}
//返回list尾节点元素
func (l *List) Back() *Element {}
//将一个值为v的新元素插入链表的第一个位置,返回生成的新元素
func (l *List) PushFront(v interface{}) *Element {}                   
//创建链表other的拷贝,并将拷贝的最后一个位置连接到list的第一个位置
func (l *List) PushFrontList(other *List) {}
//将一个值为v的新元素插入链表的第一个位置,返回生成的新元素                     
func (l *List) PushBack(v interface{}) *Element {}
//创建链表other的拷贝,并将拷贝的第一个位置连接到list的最后一个位置
func (l *List) PushBackList(other *List) {}
//将一个值为v的新元素插入到mark前面,并返回生成的新元素。如果mark不是l的元素,l不会被修改
func (l *List) InsertBefore(v interface{}, mark *Element) *Element {}
//将一个值为v的新元素插入到mark后面,并返回新生成的元素。如果mark不是l的元素,l不会被修改
func (l *List) InsertAfter(v interface{}, mark *Element) *Element {}
//将元素e移动到链表的第一个位置,如果e不是l的元素,l不会被修改
func (l *List) MoveToFront(e *Element) {}
//将元素e移动到链表的最后一个位置,如果e不是l的元素,l不会被修改
func (l *List) MoveToBack(e *Element) {}
//将元素e移动到mark的前面。如果e或mark不是l的元素,或者e==mark,l不会被修改
func (l *List) MoveBefore(e, mark *Element) {}
//将元素e移动到mark的后面。如果e或mark不是l的元素,或者e==mark,l不会被修改
func (l *List) MoveAfter(e, mark *Element) {}
//删除链表中的元素e,并返回e.Value
func (l *List) Remove(e *Element) interface{} {}

container/list 标准库中代码实现巧妙,包括延迟初始化、封装设计等技巧,对小白(like me)有很好的借鉴意义。

这里摘出来几个片段

Remove实现了对内部remove的封装

func (l *List) remove(e *Element) *Element {
	e.prev.next = e.next
	e.next.prev = e.prev
	e.next = nil // avoid memory leaks
	e.prev = nil // avoid memory leaks
	e.list = nil
	l.len--
	return e
}

func (l *List) Remove(e *Element) interface{} {
	if e.list == l {
		l.remove(e)
	}
	return e.Value
}

MoveBefore和PushBackList都是对基本操作的调用

func (l *List) MoveBefore(e, mark *Element) {
	if e.list != l || e == mark || mark.list != l {
		return
	}
	l.insert(l.remove(e), mark.prev)
}

func (l *List) PushBackList(other *List) {
	l.lazyInit()
	for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
		l.insertValue(e.Value, l.root.prev)
	}
}

list包使用示例

其中使用几个代表性方法

package main

import (
	"container/list"
	"fmt"
)

func main() {
	l := list.New()
	l.PushFront(1)                // 1
	l.PushBack(2)                 // 1->2
	fmt.Println(l.Front().Value)  // 1
	fmt.Println(l.Back().Value)   // 2
	other := list.New()
	other.PushFront(3)
	other.PushBack(4)
	l.PushFrontList(other)        // 3->4->1->2
	fmt.Println(l.Front().Value)
	fmt.Println(l.Back().Value)
	fmt.Println(l.Len())
	l.Remove(l.Front().Next())    // 3->1->2
	fmt.Println(l.Len())
	for v := l.Front(); v != nil; v = v.Next() {
		fmt.Printf("%d ", v.Value)
	}
	fmt.Printf("\n")
}

 

猜你喜欢

转载自blog.csdn.net/Lazyboy_/article/details/88195207