go语言列表list

本文介绍了Go语言中使用container/list包实现的列表操作,包括初始化列表、在列表中插入和删除元素,以及遍历列表的方法。重点讲解了PushFront、PushBack方法以及如何通过*list.Element高效删除元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在 Go 语言中,将列表使用 container/list 包来实现,内部的实现原理是双链表。列表能够高效地进行任意位置的元素插入和删除操作。

初始化列表

list 的初始化有两种方法:New 和声明。两种方法的初始化效果都是一致的。

  1. 通过 container/list 包的 New 方法初始化 list
    变量名 := list.New()
  2. 通过声明初始化list
    var 变量名 list.List

列表与切片和 map 不同的是,列表并没有具体元素类型的限制。因此,列表的元素可以是任意类型。这既带来便利,也会引来一些问题。给一个列表放入了非期望类型的值,在取出值后,将 interface{} 转换为期望类型时将会发生宕机。

在列表中插入元素

双链表支持从队列前方或后方插入元素,分别对应的方法是 PushFront 和 PushBack
提示 这两个方法都会返回一个 *list.Element 结构。如果在以后的使用中需要删除插入的元素,则只能通过 *list.Element 配合 Remove() 方法进行删除,这种方法可以让删除更加效率化,也是双链表特性之一。
下面代码展示如何给list添加元素:

l := list.New()
l.PushBack("fist")
l.PushFront(67)

代码说明如下:

  • 第 1 行,创建一个列表实例。
  • 第 3 行,将 fist 字符串插入到列表的尾部,此时列表是空的,插入后只有一个元素。
  • 第 4 行,将数值 67 放入列表。此时,列表中已经存在 fist 元素,67 这个元素将被放在 fist 的前面。

定义List结构体

type List struct {
 root Node // 头节点
 length int // list长度
}

因为在定义List数据结构的时候,就定义了一个root头节点。所以此时,可以很方便的实现头插入和尾插入。考虑能够同时插入多个/一个Node节点,利用Go中的变长参数实现该特性。对插入的Node节点进行循环处理,新节点的指针域和root节点的指针域做相应改变,具体实现方式以及说明在代码中说明:

func (l *List) PushFront(elements ...interface{}) {
 for _, element := range elements {
 n := &Node{Value: element} // 注释一
 n.next = l.root.next // 新节点的next是root节点的next
 n.prev = &l.root // 新节点的prev存储的是root的地址
 l.root.next.prev = n // 原来root节点的next的prev是新节点
 l.root.next = n // 头插法 root 之后始终是新节点
 l.length++ // list 长度加1
 }
}

从列表中删除元素

列表的插入函数的返回值会提供一个 *list.Element 结构,这个结构记录着列表元素的值及和其他节点之间的关系等信息。从列表中删除元素时,需要用到这个结构进行快速删除。
列表操作元素:

package main

import "container/list"

func main() {
    l := list.New()
    
    // 尾部添加
    l.PushBack("canon")
    
    // 头部添加
    l.PushFront(67)
    
    // 尾部添加后保存元素句柄
    element := l.PushBack("fist")
    
    // 在fist之后添加high
    l.InsertAfter("high", element)
    
    // 在fist之前添加noon
    l.InsertBefore("noon", element)
    
    // 使用
    l.Remove(element)
}

代码说明如下:

  • 第 6 行,创建列表实例。
  • 第 9 行,将 canon 字符串插入到列表的尾部。
  • 第 12 行,将 67 数值添加到列表的头部。
  • 第 15 行,将 fist 字符串插入到列表的尾部,并将这个元素的内部结构保存到 element 变量中。
  • 第 18 行,使用 element 变量,在 element 的位置后面插入 high 字符串。
  • 第 21 行,使用 element 变量,在 element 的位置前面插入 noon 字符串。
  • 第 24 行,移除 element 变量对应的元素。

遍历列表——访问列表的每一个元素

遍历双链表需要配合 Front() 函数获取头元素,遍历时只要元素不为空就可以继续进行。每一次遍历调用元素的 Next,如代码中第 9 行所示。

l := list.New()

// 尾部添加
l.PushBack("canon")

// 头部添加
l.PushFront(67)

for i := l.Front(); i != nil; i = i.Next() {
    fmt.Println(i.Value)
}

代码输出如下:

67
canon

代码说明如下:

  • 第 1 行,创建一个列表实例。
  • 第 4 行,将 canon 放入列表尾部。
  • 第 7 行,在队列头部放入 67。
  • 第 9 行,使用 for 语句进行遍历,其中 i:=l.Front() 表示初始赋值,只会在一开始执行一次;每次循环会进行一次 i!=nil 语句判断,如果返回 false,表示退出循环,反之则会执行 i=i.Next()。
  • 第 10 行,使用遍历返回的 *list.Element 的 Value 成员取得放入列表时的原值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值