列表是一种非连续存储的容器,由多个节点组成,节点通过一些变量记录彼此之间的关系。列表有多种实现方法,如单链表、双链表等。
在 Go
语言中,将列表使用 container/list
包来实现,内部的实现原理是双链表。列表能够高效地进行任意位置的元素插入和删除操作。
1. 列表初始化
list
的初始化有两种方法: New
和声明。两种方法的初始化效果都是一致的。
1.1 通过 New方法初始化 list
变量名 :=list.New()
1.2 通过声明初始化 list
var 变量名 list.List
列表与切片和 map
不同的是,列表并没有具体元素类型的限制。因此,列表的元素可以是任意类型。这既带来便利,也会引来一些问题。给一个列表放入了非期望类型的值,在取出值后,将 interface{}
转换为期望类型时将会发生宕机 。
2. 列表中插入元素
双链表支持从队列前方或后方插入元素,分别对应的方法是 PushFront
和 PushBack
。这两个方法都会返回 一个 *list.Element
结构。如果在以后的使用中需要删除插入的元素,则只能通过 *list.Element
配合 Remove()
方法进行删除,这种方法可以让删除更加效率化,也是双链表特性之一 。
l := list.New()
l.PushBack("last")
l.PushFront(100)
3. 列表中删除元素
列表的插入函数的返回值会提供一个 *list.Element
结构,这个结构记录着列表元素的值及和其他节点之间的 关系等信息。从列表中删除元素时,需要用到这个结构进行快速删除。
package main
import "container/list"
func main() {
l := list.New()
l.PushBack("last")
l.PushFront(100)
element := l.PushBack("back")
// back 之后添加元素
l.InsertAfter("back_after", element)
// back 之前添加元素
l.InsertBefore("back_fornt", element)
// 删除 element 变量对应的元素。
l.Remove(element)
}
4. 列表遍历
遍历双链表需要配合 Front()
函数获取头元素,遍历时只要元素不为空就可以继续进行。每一次遍历调用元素的 Next
。
package main
import (
"container/list"
"fmt"
)
func main() {
l := list.New()
l.PushBack("last")
l.PushFront(100)
element := l.PushBack("back")
// back 之后添加元素
l.InsertAfter("back_after", element)
// back 之前添加元素
l.InsertBefore("back_fornt", element)
fmt.Println("删除前")
for i := l.Front(); i != nil; i = i.Next() {
fmt.Println(i.Value)
}
// 删除 element 变量对应的元素。
fmt.Println("删除后")
l.Remove(element)
for i := l.Front(); i != nil; i = i.Next() {
fmt.Println(i.Value)
}
}
其中,l.Front()
表示初始值,输出结果如下:
删除前
100
last
back_fornt
back
back_after
删除后
100
last
back_fornt
back_after