2.9 Go 双向链表

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点,相对于单链表来讲:往前往后遍历都很方便。

相对于单向链表优势:

  • 可以双向遍历

Go 双向链表 - 图1

  • 插入删除不需要移动元素外,可以原地插入删除效率更高,当然这也是以牺牲存储空间为代价。

插入数据

Go 双向链表 - 图2

删除数据

Go 双向链表 - 图3

Go container/list包

实现了基本的双向链表功能,包括元素的插入、删除、移动功能

  1. package main
  2. import (
  3. "container/list"
  4. "fmt"
  5. )
  6. func main() {
  7. l := list.New()
  8. //末尾插入值为1的元素,并返回该元素。
  9. v1 := l.PushBack(1)
  10. //首部插入值为2的元素,并返回该元素
  11. v2 := l.PushFront(2)
  12. //在元素v1前插入3
  13. l.InsertBefore(3, v2)
  14. //在元素v1后插入4
  15. l.InsertAfter(4, v1)
  16. fmt.Printf("len: %v\n", l.Len())
  17. fmt.Printf("first: %#v\n", l.Front())
  18. fmt.Printf("second: %#v\n", l.Front().Next())
  19. // 遍历列表并打印其内容。
  20. for e := l.Front(); e != nil; e = e.Next() {
  21. fmt.Println(e.Value)
  22. }
  23. }

类型元素

func (e Element) Next() Element //返回该元素的下一个元素,如果没有下一个元素则返回nil。 func (e Element) Prev() Element//返回该元素的前一个元素,如果没有前一个元素则返回nil。

类型列表

func New() List //返回一个初始化的list func (l List) Back() Element //获取list l的最后一个元素 func (l List) Front() Element //获取list l的第一个元素 func (l List) Init() List //list l初始化或者清除list l func (l List) InsertAfter(v interface{}, mark Element) Element //在list l中元素mark之后插入一个值为v的元素,并返回该元素,如果mark不是list中元素,则list不改变。 func (l List) InsertBefore(v interface{}, mark Element) Element//在list l中元素mark之前插入一个值为v的元素,并返回该元素,如果mark不是list中元素,则list不改变。 func (l List) Len() int //获取list l的长度 func (l List) MoveAfter(e, mark Element) //将元素e移动到元素mark之后,如果元素e或者mark不属于list l,或者e==mark,则list l不改变。 func (l List) MoveBefore(e, mark Element)//将元素e移动到元素mark之前,如果元素e或者mark不属于list l,或者e==mark,则list l不改变。 func (l List) MoveToBack(e Element)//将元素e移动到list l的末尾,如果e不属于list l,则list不改变。 func (l List) MoveToFront(e Element)//将元素e移动到list l的首部,如果e不属于list l,则list不改变。 func (l List) PushBack(v interface{}) Element//在list l的末尾插入值为v的元素,并返回该元素。 func (l List) PushBackList(other List)//在list l的尾部插入另外一个list,其中l和other可以相等。 func (l List) PushFront(v interface{}) Element//在list l的首部插入值为v的元素,并返回该元素。 func (l List) PushFrontList(other List)//在list l的首部插入另外一个list,其中l和other可以相等。

详见container/list

小结:

由于container/list不是并发安全的,可以通过加锁(sync.Mutex)来解决。

双向链表的优点在于快速插入和删除,适用于频繁插入、删除的场景。和slice、数组比,slice、数组的优势在于查询和遍历,适用于频发查询、遍历的场景。

links