详解go语言单链表及其常用方法的实现

详解Go语言单链表及其常用方法的实现

什么是单链表

单链表是一种常见的数据结构,它由一系列节点组成。每个节点分为两个部分,第一个部分存储当前节点的值,第二个部分存储下一个节点的地址。最后一个节点指向空(null)。单链表中保存的数据不存在顺序关系,且每个节点仅知道下一个节点的地址,不知道前一个节点的地址。因此,无法随机访问单链表中的元素,只能从链表的头部一个一个地遍历各个节点。

在Go语言中实现单链表

定义单链表节点的结构体

在Go语言中,可以使用结构体来定义单链表中的节点。结构体包含两个属性:Value表示当前节点存储的值,Next表示下一个节点的地址。

type ListNode struct {
    Value interface{} // 存储的值,使用interface{}可以保存任何类型的数据
    Next  *ListNode   // 下一个节点的地址
}

定义单链表结构体

定义单链表结构体,包含头结点和当前链表长度。头结点不存储任何值,仅用来标识链表的开始位置。

type LinkedList struct {
    head  *ListNode // 头结点
    count int       // 当前链表长度
}

实现单链表的初始化方法

初始化单链表时,仅需要创建一个头结点,并将链表长度设置为0。

func (list *LinkedList) Init() {
    list.head = new(ListNode) // 创建头结点
    list.count = 0           // 链表长度为0
}

实现单链表的获取长度方法

链表长度是记录在链表结构体中的一个属性,只需要返回该属性的值即可。

func (list *LinkedList) Len() int {
    return list.count
}

实现单链表的添加节点方法

链表中最常用的操作之一是添加节点。在单链表中,添加节点指的是将新节点插入到链表的末尾。

func (list *LinkedList) Append(value interface{}) {
    node := &ListNode{Value: value} // 创建新节点
    tail := list.head

    for tail.Next != nil {
        tail = tail.Next // 获取最后一个节点的地址
    }

    tail.Next = node // 将新节点添加到链表的末尾
    list.count++     // 更新链表长度
}

实现单链表的查找节点方法

在单链表中,查找节点指的是根据节点的值,从头结点开始寻找该节点。

func (list *LinkedList) Find(value interface{}) *ListNode {
    cur := list.head.Next // 从第一个节点开始查找

    for cur != nil {
        if cur.Value == value {
            return cur // 查找到节点
        }

        cur = cur.Next // 继续查找下一个节点
    }

    return nil // 没有找到节点
}

示例1:使用单链表保存任务列表

func main() {
    // 初始化单链表
    taskList := new(LinkedList)
    taskList.Init()

    // 添加任务到链表中
    taskList.Append("任务1")
    taskList.Append("任务2")
    taskList.Append("任务3")
    taskList.Append("任务4")

    // 在任务列表中查找指定任务
    task := taskList.Find("任务3")
    if task != nil {
        fmt.Println("找到任务:", task.Value)
    } else {
        fmt.Println("未找到任务")
    }
}

示例2:使用单链表实现LRU缓存

type LRUCache struct {
    cap     int           // 缓存容量
    cache   map[int]*Node // 缓存中的节点
    head    *Node         // 头结点
    tail    *Node         // 尾节点
    current int           // 当前链表长度
}

type Node struct {
    key   int  // 缓存键
    value int  // 缓存值
    prev  *Node
    next  *Node
}

func NewLRUCache(cap int) *LRUCache {
    cache := &LRUCache{
        cap:   cap,
        cache: make(map[int]*Node),
        head:  new(Node),
        tail:  new(Node),
    }

    cache.head.next = cache.tail
    cache.tail.prev = cache.head

    return cache
}

func (cache *LRUCache) Put(key int, value int) {
    node, ok := cache.cache[key]

    if !ok {
        node = &Node{key: key, value: value}
        cache.cache[key] = node
        cache.current++

        if cache.current > cache.cap {
            cache.Remove(cache.tail.prev)
        }
    } else {
        node.value = value
        cache.Remove(node)
    }

    cache.MoveToFront(node)
}

func (cache *LRUCache) Remove(node *Node) {
    node.prev.next = node.next
    node.next.prev = node.prev
    delete(cache.cache, node.key)
    cache.current--
}

func (cache *LRUCache) MoveToFront(node *Node) {
    node.prev = cache.head
    node.next = cache.head.next
    cache.head.next.prev = node
    cache.head.next = node
}

func (cache *LRUCache) Get(key int) int {
    node, ok := cache.cache[key]

    if !ok {
        return -1
    }

    cache.MoveToFront(node)

    return node.value
}

以上是单链表及其常用方法的实现。通过示例,可以看到单链表的应用非常广泛,可以用于任务列表、LRU缓存等场景。本文实现的单链表类似于Go标准库中的container/list包,读者可以自行比较并学习。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解go语言单链表及其常用方法的实现 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • tensorflow如何提高gpu训练效率和利用率

    TensorFlow如何提高GPU训练效率和利用率 TensorFlow是目前最流行的深度学习框架之一,其具有高效的自动微分计算和强大的GPU加速能力。然而,在实际的深度学习训练过程中,GPU的利用率和训练效率往往成为瓶颈。本文将介绍一些TensorFlow提高GPU训练效率和利用率的技巧和方法。 1. 使用数据增强 在深度学习训练中,数据增强是提高模型泛化…

    其他 2023年3月29日
    00
  • Java反射之静态加载和动态加载的简单实例

    下面是详细的攻略: Java反射之静态加载和动态加载的简单实例 什么是Java反射 Java反射是指在运行时动态获取一个类的信息,并动态调用它的方法、构造函数等的能力。Java反射机制提供了一种动态加载类和访问类的方式,能够增强程序的灵活性和扩展性。 反射的基本概念 Class类:Java反射机制的核心类,所有的类在载入时都会生成一个Class类的实例。 C…

    other 2023年6月25日
    00
  • Android Beam 文件传输失败分析与解决方法

    Android Beam 文件传输失败分析与解决方法 问题描述 在使用 Android Beam 进行文件传输时,有时会遇到传输失败的问题。该问题的具体表现为,在两个设备相互对接并尝试传输文件时,触碰成功后没有出现文件传输界面,或者传输界面出现后传输一段时间后失败,提示“文件传输失败”。 问题分析 从提示信息来看,文件传输过程中出现了错误,但具体的错误原因不…

    other 2023年6月26日
    00
  • ubuntu版本查看命令

    Ubuntu版本查看命令 在使用Ubuntu操作系统时,我们需要经常查看系统的版本信息。本文将介绍几种常用的Ubuntu版本查看命令。 lsb_release命令 lsb_realease 命令是用于查看系统发行版信息的命令。该命令可以查看Ubuntu的版本号、描述、CodeName等信息。 lsb_release -a 上述命令会输出系统的版本信息,如下所…

    其他 2023年3月29日
    00
  • body测试onclick等鼠标事件无效果详解

    下面是“body测试onclick等鼠标事件无效果详解的完整攻略”,包括问题分析、解决方法和两个示例说明等方面。 问题分析 在使用onclick等鼠标事件时,有时会出现无效果的情况。这种情况可能是由于以下原因导致的: 代码错误:代码中可能存在语法错误或逻辑错误,导致鼠标事件无法正常触发; 元素不存在:鼠标事件绑定的元素可能不存在,导致事件无法触发; 元素被覆…

    other 2023年5月5日
    00
  • 什么是物理内存与虚拟内存 各指什么

    什么是物理内存与虚拟内存 物理内存 物理内存是计算机中用于存储数据和程序的硬件设备,也被称为主存或随机存储器(RAM)。它是计算机的实际内存,用于存储正在运行的程序和数据。物理内存的大小通常以字节为单位进行衡量,例如兆字节(MB)或千兆字节(GB)。 物理内存的主要作用是提供给操作系统和应用程序一个快速访问数据的空间。当程序运行时,它的指令和数据被加载到物理…

    other 2023年8月1日
    00
  • Android实现简洁的APP登录界面

    Android实现简洁的APP登录界面攻略 1. 设计登录界面布局 首先,我们需要设计一个简洁而吸引人的登录界面布局。可以使用XML布局文件来定义界面元素的位置和样式。以下是一个示例的登录界面布局: <LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android…

    other 2023年9月6日
    00
  • ubuntu安装python3.6

    以下是关于“Ubuntu安装Python3.6”的完整攻略,包括基本概念、步骤和两个示例。 基本概念 Python是一种流行的编程语言,可以用于开发Web应用、数据分析、人工智能等领域。在Ubuntu操作系统中,可以使用apt命令安装Python3.6。 步骤 以下是在Ubuntu操作系统中安装Python3.6的步骤: 更新软件包列表:使用apt-get命…

    other 2023年5月7日
    00
合作推广
合作推广
分享本页
返回顶部