前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go标准库:container/list

Go标准库:container/list

原创
作者头像
孟斯特
发布2024-07-03 16:01:53
720
发布2024-07-03 16:01:53
举报
文章被收录于专栏:Go学习Go学习

在Go语言的标准库中,container/list包提供了一个双向链表的实现,这对于需要频繁插入和删除操作的场景非常有用。双向链表是一种线性数据结构,它由一系列节点组成,每个节点包含数据和两个指针,分别指向前一个节点和后一个节点。下面我们将详细介绍如何使用container/list包,以及它的内部实现和常见操作。

导入包

首先,我们需要导入container/list包:

代码语言:go
复制
import "container/list"

初始化链表

我们可以通过调用list.New()函数或者直接声明一个list.List类型的变量来初始化一个链表:

代码语言:go
复制
// 方法一:使用list.New()函数
l := list.New()

// 方法二:直接声明一个list.List变量
var l list.List

基本操作

添加元素

container/list包提供了多种方法来向链表中添加元素:

  • PushFront(v interface{}) *Element:在链表的头部插入一个元素,返回该元素的指针。
  • PushBack(v interface{}) *Element:在链表的尾部插入一个元素,返回该元素的指针。
  • InsertBefore(v interface{}, mark *Element) *Element:在指定元素之前插入一个新元素。
  • InsertAfter(v interface{}, mark *Element) *Element:在指定元素之后插入一个新元素。
代码语言:go
复制
l := list.New()
l.PushBack("Go")
l.PushFront(42)
e := l.PushBack(3.14)
l.InsertBefore("before", e)
l.InsertAfter("after", e)

删除元素

可以使用Remove方法删除链表中的元素,Remove方法接受一个指向链表元素的指针,删除该元素并返回其值:

代码语言:go
复制
l := list.New()
e := l.PushBack("to be removed")
l.Remove(e)

遍历链表

可以使用Front()Back()方法获取链表的第一个和最后一个元素,然后通过元素的Next()Prev()方法进行遍历:

代码语言:go
复制
// 从前向后遍历
for e := l.Front(); e != nil; e = e.Next() {
    fmt.Println(e.Value)
}

// 从后向前遍历
for e := l.Back(); e != nil; e = e.Prev() {
    fmt.Println(e.Value)
}

链表的特性

  • 双向链表:每个节点有两个指针,分别指向前一个节点和后一个节点。
  • O(1)时间复杂度的插入和删除:链表的插入和删除操作都只需要调整指针,因此效率很高。
  • 遍历效率较低:由于链表节点不连续存储,无法利用CPU缓存,遍历效率相对于数组较低。

常见应用场景

  1. 需要频繁插入和删除操作的场景:由于链表插入和删除操作的时间复杂度为O(1),在需要频繁进行这些操作时,链表表现优异。
  2. 实现LRU缓存:链表和哈希表的结合可以高效实现LRU(最近最少使用)缓存。
  3. 队列和双端队列:链表可以方便地实现FIFO队列和双端队列。

示例:实现一个简单的LRU缓存

下面是一个使用container/listmap实现的简单LRU缓存的例子:

代码语言:go
复制
package main

import (
    "container/list"
    "fmt"
)

type LRUCache struct {
    capacity int
    list     *list.List
    cache    map[int]*list.Element
}

type entry struct {
    key   int
    value int
}

func NewLRUCache(capacity int) *LRUCache {
    return &LRUCache{
        capacity: capacity,
        list:     list.New(),
        cache:    make(map[int]*list.Element),
    }
}

func (c *LRUCache) Get(key int) (int, bool) {
    if e, ok = c.cache[key]; ok {
        c.list.MoveToFront(e)
        return e.Value.(*entry).value, true
    }
    return -1, false
}

func (c *LRUCache) Put(key, value int) {
    if e, ok = c.cache[key]; ok {
        c.list.MoveToFront(e)
        e.Value.(*entry).value = value
    } else {
        if c.list.Len() == c.capacity {
            back := c.list.Back()
            c.list.Remove(back)
            delete(c.cache, back.Value.(*entry).key)
        }
        e := &entry{key, value}
        listElement := c.list.PushFront(e)
        c.cache[key] = listElement
    }
}

func main() {
    cache := NewLRUCache(2)
    cache.Put(1, 1)
    cache.Put(2, 2)
    fmt.Println(cache.Get(1)) // 返回1
    cache.Put(3, 3)
    fmt.Println(cache.Get(2)) // 返回-1 (未找到)
    cache.Put(4, 4)
    fmt.Println(cache.Get(1)) // 返回-1 (未找到)
    fmt.Println(cache.Get(3)) // 返回3
    fmt.Println(cache.Get(4)) // 返回4
}

我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!


原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导入包
  • 初始化链表
  • 基本操作
    • 添加元素
      • 删除元素
        • 遍历链表
        • 链表的特性
        • 常见应用场景
        • 示例:实现一个简单的LRU缓存
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档