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