Go 语言的链表实现在标准库的container/list代码包中。这个代码包中有两个公开的程序实体——List和Element,List 实现了一个双向链表(以下简称链表),而 Element 则代表了链表中元素的结构。
包中方法:MoveBefore方法和MoveAfter方法,它们分别用于把给定的元素移动到另一个元素的前面和后面。MoveToFront方法和MoveToBack方法,分别用于把给定的元素移动到链表的最前端和最后端。
在这些方法中,“给定的元素”都是*Element类型的,*Element类型是Element类型的指针类型,*Element的值就是元素的指针。
func (l *List) MoveBefore(e, mark *Element) func (l *List) MoveAfter(e, mark *Element) func (l *List) MoveToFront(e *Element) func (l *List) MoveToBack(e *Element)
在List包含的方法中,用于插入新元素的那些方法都只接受interface{}类型的值。这些方法在内部会使用Element值,包装接收到的新元素。
List的方法还有下面这几种:
- Front和Back方法分别用于获取链表中最前端和最后端的元素,
- InsertBefore和InsertAfter方法分别用于在指定的元素之前和之后插入新元素,
- PushFront和PushBack方法则分别用于在链表的最前端和最后端插入新元素。
func (l *List) Front() *Element func (l *List) Back() *Element func (l *List) InsertBefore(v interface{}, mark *Element) *Element func (l *List) InsertAfter(v interface{}, mark *Element) *Element func (l *List) PushFront(v interface{}) *Element func (l *List) PushBack(v interface{}) *Element
这些方法都会把一个Element值的指针作为结果返回,它们就是链表留给我们的安全“接口”。拿到这些内部元素的指针,我们就可以去调用前面提到的用于移动元素的方法了。
List和Element都是结构体类型。结构体类型有一个特点,那就是它们的零值都会是拥有特定结构,但是没有任何定制化内容的值,相当于一个空壳。值中的字段也都会被分别赋予各自类型的零值。
广义来讲,所谓的零值就是只做了声明,但还未做初始化的变量被给予的缺省值。每个类型的零值都会依据该类型的特性而被设定。
比如,经过语句var a [2]int声明的变量a的值,将会是一个包含了两个0的整数数组。又比如,经过语句var s []int声明的变量s的值将会是一个[]int类型的、值为nil的切片。
实际上,Go 语言的切片就起到了延迟初始化其底层数组的作用,你可以想一想为什么会这么说的理由。延迟初始化的缺点恰恰也在于“延后”。你可以想象一下,如果我在调用链表的每个方法的时候,它们都需要先去判断链表是否已经被初始化,那这也会是一个计算量上的浪费。在这些方法被非常频繁地调用的情况下,这种浪费的影响就开始显现了,程序的性能将会降低。
在这里的链表实现中,一些方法是无需对是否初始化做判断的。比如Front方法和Back方法,一旦发现链表的长度为0, 直接返回nil就好了。
又比如,在用于删除元素、移动元素,以及一些用于插入元素的方法中,只要判断一下传入的元素中指向所属链表的指针,是否与当前链表的指针相等就可以了。
如果不相等,就一定说明传入的元素不是这个链表中的,后续的操作就不用做了。反之,就一定说明这个链表已经被初始化了。
原因在于,链表的PushFront方法、PushBack方法、PushBackList方法以及PushFrontList方法总会先判断链表的状态,并在必要时进行初始化,这就是延迟初始化。
package main import ( "container/list" "fmt" ) func main() { // 创建一个 list l := list.New() //把4元素放在最后 e4 := l.PushBack(4) //把1元素放在最前 e1 := l.PushFront(1) //在e4元素前面插入3 l.InsertBefore(3, e4) //在e1后面插入2 l.InsertAfter(2, e1) // 遍历所有元素并打印其内容 for e := l.Front(); e != nil; e = e.Next() { fmt.Println(e.Value) } }
输出:
1
2
3
4
package main import ( "container/list" "fmt" ) func main() { // 创建一个 list l := list.New() //把4元素放在最后 e4 := l.PushBack(4) //把1元素放在最前 e1 := l.PushFront(1) //在e4元素前面插入3 l.InsertBefore(3, e4) //在e1后面插入2 e2 := l.InsertAfter(2, e1) // 遍历所有元素并打印其内容 fmt.Println(" 元素 ") for e := l.Front(); e != nil; e = e.Next() { fmt.Print(e.Value, " ") } //获取l 最前的元素 et1 := l.Front() fmt.Println("list 最前的元素 Front ", et1.Value) //获取l 最后的元素 et2 := l.Back() fmt.Println("list 最后的元素 Back ", et2.Value) //获取l的长度 fmt.Println("list 的长度为: Len ", l.Len()) //向后移动 l.MoveAfter(e1, e2) fmt.Println("把1元素移动到2元素的后面 向后移动后 MoveAfter :") for e := l.Front(); e != nil; e = e.Next() { fmt.Print(e.Value, " ") } //向前移动 l.MoveBefore(e1, e2) fmt.Println(" 把1元素移动到2元素的前面 向前移动后 MoveBefore :") for e := l.Front(); e != nil; e = e.Next() { fmt.Print(e.Value, " ") } //移动到最后面 l.MoveToBack(e1) fmt.Println(" 1元素出现在最后面 MoveToBack ") for e := l.Front(); e != nil; e = e.Next() { fmt.Print(e.Value, " ") } //移动到最前面 l.MoveToFront(e1) fmt.Println(" 1元素出现在最前面 MoveToFront ") for e := l.Front(); e != nil; e = e.Next() { fmt.Print(e.Value, " ") } //删除元素 fmt.Println("") l.Remove(e1) fmt.Println(" e1元素移除后 Remove ") for e := l.Front(); e != nil; e = e.Next() { fmt.Print(e.Value, " ") } // init 可以用作 clear l.Init() fmt.Println(" list init()后 ") for e := l.Front(); e != nil; e = e.Next() { fmt.Print(e.Value, " ") } fmt.Println("list 的长度Init ", l.Len()) //向前移动 // }
输出:
元素
1 2 3 4 list 最前的元素 Front 1
list 最后的元素 Back 4
list 的长度为: Len 4
把1元素移动到2元素的后面 向后移动后 MoveAfter :
2 1 3 4
把1元素移动到2元素的前面 向前移动后 MoveBefore :
1 2 3 4
1元素出现在最后面 MoveToBack
2 3 4 1
1元素出现在最前面 MoveToFront
1 2 3 4
e1元素移除后 Remove
2 3 4
list init()后
list 的长度Init 0
func (*List) PushFrontList func (*List) PushBackList
这种两者方法可以批量向链表后端或者链表前端添加元素
package main import ( "container/list" "fmt" ) func main() { l := list.New() //把4元素放在最后 e4 := l.PushBack(4) //把1元素放在最前 e1 := l.PushFront(1) //在e4元素前面插入3 l.InsertBefore(nil, e4) //在e4元素前面插入3 l.InsertAfter("123132", e1) fmt.Println(" 元素 ") for e := l.Front(); e != nil; e = e.Next() { fmt.Print(e.Value, " ") } }
输出:
元素
1 123132 <nil> 4