golang学习笔记---container/list

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("\n把1元素移动到2元素的前面 向前移动后 MoveBefore :")
	for e := l.Front(); e != nil; e = e.Next() {
		fmt.Print(e.Value, " ")
	}
	//移动到最后面
	l.MoveToBack(e1)
	fmt.Println("\n 1元素出现在最后面 MoveToBack ")
	for e := l.Front(); e != nil; e = e.Next() {
		fmt.Print(e.Value, " ")
	}
	//移动到最前面
	l.MoveToFront(e1)
	fmt.Println("\n 1元素出现在最前面 MoveToFront ")
	for e := l.Front(); e != nil; e = e.Next() {
		fmt.Print(e.Value, " ")
	}
	//删除元素
	fmt.Println("")
	l.Remove(e1)
	fmt.Println("\n e1元素移除后 Remove ")
	for e := l.Front(); e != nil; e = e.Next() {
		fmt.Print(e.Value, " ")
	}
	// init 可以用作 clear
	l.Init()
	fmt.Println("\n 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

 

posted on 2021-10-25 15:25  清明-心若淡定  阅读(744)  评论(0编辑  收藏  举报