• 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("
    把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

  • 相关阅读:
    English trip V1
    English trip M1
    every day a practice —— morning(5)
    English Voice of <<All Of Me>>
    bzoj 3561 DZY Loves Math VI
    luogu P4322 [JSOI2016]最佳团体
    luogu P3264 [JLOI2015]管道连接
    bzoj 5084 hashit
    luogu P6091 原根
    bzoj 5206 [Jsoi2017]原力
  • 原文地址:https://www.cnblogs.com/saryli/p/15458781.html
Copyright © 2020-2023  润新知