掌握Go语言:Go语言链表精解,揭秘高效数据结构,应用场景全揭秘(17)

链表常用方法详解

链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据元素和指向下一个节点的指针。在Go语言中,链表的常用方法包括插入节点、删除节点、查找节点、反转链表以及获取链表长度。下面将逐一详解这些方法,并提供相应的示例。

1. 插入节点

在链表中插入新节点的方法有多种,可以在链表头部、尾部或指定位置插入节点。以下是一些常见的插入节点方法:

  • 头部插入:在链表头部插入新节点,使其成为新的头节点。
  • 尾部插入:在链表尾部插入新节点,使其成为新的尾节点。
  • 指定位置插入:在链表的指定位置插入新节点,需要找到插入位置的前一个节点,并调整指针连接。

示例代码:

// 头部插入
func (l *LinkedList) InsertAtHead(val int) {newNode := &ListNode{Val: val, Next: l.Head}l.Head = newNode
}// 尾部插入
func (l *LinkedList) InsertAtTail(val int) {newNode := &ListNode{Val: val}if l.Head == nil {l.Head = newNodereturn}cur := l.Headfor cur.Next != nil {cur = cur.Next}cur.Next = newNode
}// 指定位置插入
func (l *LinkedList) InsertAtIndex(index, val int) {if index == 0 {l.InsertAtHead(val)return}newNode := &ListNode{Val: val}cur := l.Headfor i := 0; i < index-1 && cur != nil; i++ {cur = cur.Next}if cur == nil {return}newNode.Next = cur.Nextcur.Next = newNode
}
2. 删除节点

从链表中删除节点的方法可以根据节点值或位置进行删除。以下是一些常见的删除节点方法:

  • 根据值删除:删除链表中指定值的节点。
  • 根据位置删除:删除链表中指定位置的节点,需要找到待删除节点的前一个节点,并调整指针连接。

示例代码:

// 根据值删除
func (l *LinkedList) DeleteNodeByValue(val int) {if l.Head == nil {return}if l.Head.Val == val {l.Head = l.Head.Nextreturn}prev := l.Headfor prev.Next != nil && prev.Next.Val != val {prev = prev.Next}if prev.Next != nil {prev.Next = prev.Next.Next}
}// 根据位置删除
func (l *LinkedList) DeleteNodeByIndex(index int) {if index == 0 {if l.Head != nil {l.Head = l.Head.Next}return}cur := l.Headfor i := 0; i < index-1 && cur != nil; i++ {cur = cur.Next}if cur == nil || cur.Next == nil {return}cur.Next = cur.Next.Next
}
3. 查找节点

查找链表中是否存在指定值的节点是链表的常见操作之一。如果找到匹配的节点,则返回该节点的指针;如果未找到,则返回空指针。

示例代码:

// 查找节点
func (l *LinkedList) Search(val int) *ListNode {cur := l.Headfor cur != nil {if cur.Val == val {return cur}cur = cur.Next}return nil
}
4. 反转链表

反转链表是将链表中的节点顺序颠倒的操作。通过调整节点之间的指针连接,可以实现链表的反转。

示例代码:

// 反转链表
func (l *LinkedList) Reverse() {var prev *ListNodecur := l.Headfor cur != nil {next := cur.Nextcur.Next = prevprev = curcur = next}l.Head = prev
}
5. 获取链表长度

获取链表长度是衡量链表大小的重要指标之一,可以通过遍历链表并计数节点的方式来获取链表的长度。

示例代码:

// 获取链表长度
func (l *LinkedList) Length() int {length := 0cur := l.Headfor cur != nil {length++cur = cur.Next}return length
}

链表在实际应用中的应用场景

链表是一种基础的数据结构,在实际的软件开发中有着广泛的应用。下面将详细解释链表在LRU缓存、任务调度和表达式计算等场景中的具体应用,并提供相应的示例代码。

1. LRU缓存

LRU(Least Recently Used)缓存是一种常见的缓存淘汰策略,其中最近最少使用的数据会被淘汰出缓存。链表可以很好地支持LRU缓存的实现,通常使用双向链表结合哈希表来实现LRU缓存。

在双向链表中,节点按照访问时间顺序排列,越靠近链表头部的节点表示最近被访问过的数据,而靠近链表尾部的节点表示最久未被访问的数据。当需要从缓存中淘汰数据时,可以直接删除链表尾部的节点。

示例代码:

// 实现LRU缓存结构
type LRUCache struct {capacity intcache    map[int]*Nodehead     *Nodetail     *Node
}type Node struct {key   intvalue intprev  *Nodenext  *Node
}// 初始化LRU缓存
func Constructor(capacity int) LRUCache {return LRUCache{capacity: capacity,cache:    make(map[int]*Node),head:     &Node{},tail:     &Node{},}
}// 获取缓存中指定key对应的value
func (l *LRUCache) Get(key int) int {if node, ok := l.cache[key]; ok {l.moveToHead(node)return node.value}return -1
}// 将指定节点移动到链表头部
func (l *LRUCache) moveToHead(node *Node) {l.removeNode(node)l.addToHead(node)
}// 从链表中删除指定节点
func (l *LRUCache) removeNode(node *Node) {node.prev.next = node.nextnode.next.prev = node.prev
}// 将节点添加到链表头部
func (l *LRUCache) addToHead(node *Node) {node.prev = l.headnode.next = l.head.nextl.head.next.prev = nodel.head.next = node
}// 向缓存中添加数据
func (l *LRUCache) Put(key int, value int) {if node, ok := l.cache[key]; ok {node.value = valuel.moveToHead(node)} else {newNode := &Node{key:   key,value: value,}l.cache[key] = newNodel.addToHead(newNode)if len(l.cache) > l.capacity {l.removeTail()}}
}// 删除链表尾部节点
func (l *LRUCache) removeTail() {tail := l.tail.prevdelete(l.cache, tail.key)l.removeNode(tail)
}
2. 任务调度

任务调度是指根据一定的策略将任务分配给不同的执行单元(如线程、进程等)并进行执行的过程。链表可以作为任务队列的数据结构,实现任务的排队和调度。

示例代码:

// 任务调度队列结构
type TaskQueue struct {head *TaskNodetail *TaskNode
}// 任务节点结构
type TaskNode struct {task func() // 任务函数next *TaskNode
}// 初始化任务调度队列
func NewTaskQueue() *TaskQueue {return &TaskQueue{}
}// 添加任务到队列尾部
func (q *TaskQueue) AddTask(task func()) {newNode := &TaskNode{task: task}if q.head == nil {q.head = newNodeq.tail = newNode} else {q.tail.next = newNodeq.tail = newNode}
}// 从队列头部取出任务并执行
func (q *TaskQueue) ExecuteTask() {if q.head != nil {task := q.head.taskq.head = q.head.nexttask()}
}
3. 表达式计算

链表可以用于表达式的构建和计算,特别是在中缀表达式转后缀表达式的过程中,链表可以很好地支持操作符和操作数的组织和操作。

示例代码:

// 表达式节点结构
type ExprNode struct {value string // 节点值,可以是操作符或操作数next  *ExprNode
}// 中缀表达式转后缀表达式
func InfixToPostfix(infix []string) []string {var postfix []stringvar stack []*ExprNodefor _, token := range infix {if isOperand(token) {postfix = append(postfix, token)} else if token == "(" {stack = push(stack, &ExprNode{value: token})} else if token == ")" {for stack[len(stack)-1].value != "(" {postfix = append(postfix, stack[len(stack)-1].value)stack = pop(stack)}stack = pop(stack)} else {for len(stack) > 0 && precedence(stack[len(stack)-1].value) >= precedence(token) {postfix = append(postfix, stack[len(stack)-1].value)stack = pop(stack)}stack = push(stack, &ExprNode{value: token})}}for len(stack) > 0 {postfix = append(postfix, stack[len(stack)-1].value)stack = pop(stack)}return postfix
}// 判断是否为操作数
func isOperand(token string) bool {return token >= "0" && token <= "9"
}// 获取操作符的优先级
func precedence(operator string) int {if operator == "+" || operator == "-" {return 1} else if operator == "*" || operator == "/" {return 2}return 0
}// 将节点入栈
func push(stack []*ExprNode, node *ExprNode) []*ExprNode {returnappend(stack, node)
}// 将节点出栈
func pop(stack []*ExprNode) []*ExprNode {return stack[:len(stack)-1]
}

注意事项

在使用链表时,需要注意以下事项:

  • 内存泄漏:需要确保及时释放不再使用的节点内存,避免内存泄漏问题。
  • 指针操作:链表的操作涉及指针的操作,需要确保指针的正确性,防止出现空指针异常。
  • 性能问题:链表的插入、删除操作时间复杂度为O(1),但查找操作的时间复杂度为O(n),在某些场景下可能存在性能问题。

总结

本文详细介绍了链表的常用方法,包括插入节点、删除节点、查找节点、反转链表以及获取链表长度,并提供了相应的示例代码和应用场景。链表作为一种基础的数据结构,在各种场景下都有着重要的应用价值,掌握链表的基本原理和操作方法对于编写高效的Go语言程序至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/751639.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【CenterFusion】run_epoch()函数-训练一轮epoch-CenterFusion/src/lib/trainer.py

文件位置&#xff1a;CenterFusion/src/lib/trainer.py run_epoch作用&#xff1a;CenterFusion 项目训练一轮epoch过程 在 main.py 函数中&#xff0c;生成了训练器&#xff0c;然后再使用训练器训练一个 epochrun_epoch()函数的定义在src\lib\trainer.py150行左右&#xff0…

PyTorch学习笔记之激活函数篇(五)

5、PReLU函数 对应的论文链接&#xff1a;https://arxiv.org/abs/1502.01852v1 5.1 公式 PReLU函数的公式&#xff1a; f ( x ) { x , x > 0 α x , x < 0 ( α 是可训练参数 ) f(x) \begin{cases} x&,x>0 \\ \alpha x&,x<0 (\alpha 是可训练参数) …

【遍历方法】浅析Java中字符串、数组、集合的遍历

目录 前言 字符串篇 1.1 使用 for 循环和 charAt 方法 1.2 使用增强 for 循环&#xff08;forEach 循环&#xff09; 1.3 使用 Java 8 的 Stream API 最终效果 数组篇 2.1 使用普通 for 循环 2.2 使用增强型 for 循环( forEach 循环) 2.3 使用 Arrays.asList 和 forE…

解决:springboot项目访问hdfs文件提示guava版本不兼容

1、问题描述 版本说明&#xff1a;我用的hadoop版本&#xff1a;3.1.3 项目可以正常启动&#xff0c;但是调用访问hdfs的服务时候报错,报错消息如下&#xff1a;com.google.common.base.preconditions.checkArgument(ZL java/lang/String;Ljava/lang/Object:)V 原因分析&#x…

Flutter开发进阶之使用工具效率开发

Flutter开发进阶之使用工具效率开发 软件开发团队使用Flutter开发的原因通常是因为Flutter开发性能高、效率高、兼容性好、可拓展性高&#xff0c;作为软件PM来说主要考虑的是范围管理、进度管理、成本管理、资源管理、质量管理、风险管理和沟通管理等&#xff0c;可以看到Flu…

企业内部培训考试系统培训计划功能说明

培训计划是预设好的一套课程系列&#xff0c;包含课程和考试&#xff0c;分多个阶段&#xff0c;每完成一个阶段就会在学习地图上留下标记&#xff0c;让用户看到自己的努力成果&#xff0c;增强成就感&#xff0c;从而坚持完成课程。 企业内部培训考试系统中如何设置培训计划…

基于springboot的购物商城管理系统

1.项目简介 1.1 用户简介 用户主要分为管理员和用户端&#xff1a; 管理员&#xff1a; 管理员可以对后台数据进行管理、拥有最高权限、具体权限有登录后进行首页轮播图的配置管理、商品的配置、新品家具商城的配置管理、、家具商城分类管理配置、家具商城详情商品管理、用户…

Git 下载时需要使用代理?

食用方法 在命令行中&#xff0c;你可以使用以下命令来设置Git的HTTP和HTTPS代理&#xff1a; git config --global http.proxy http://127.0.0.1:6890 git config --global https.proxy https://127.0.0.1:6890 注意是根据自己的实际情况修改IP和端口号 注意如果不想全局配置…

react-面试题

一、组件基础 1. React 事件机制 <div onClick{this.handleClick.bind(this)}>点我</div> React并不是将click事件绑定到了div的真实DOM上&#xff0c;而是在document处监听了所有的事件&#xff0c;当事件发生并且冒泡到document处的时候&#xff0c;React将事…

网络安全JavaSE第二天(持续更新)

3. 基本数据与运算 3.6 运算符 3.6.1 算术运算符 在 Java 中&#xff0c;算术运算符包含&#xff1a;、-、*、/、% public class ArithmeticOperator { public static void main(String[] args) { int a 10; // 定义了一个整型类型的变量 a&#xff0c;它的值是 10 int b …

区块链推广海外市场怎么做,CloudNEO服务商免费为您定制个性化营销方案

随着区块链技术的不断发展和应用场景的扩大&#xff0c;区块链项目希望能够进入海外市场并取得成功已成为越来越多公司的目标之一。然而&#xff0c;要在海外市场推广区块链项目&#xff0c;需要采取有效的营销策略和措施。作为您的区块链项目营销服务商&#xff0c;CloudNEO将…

后端程序员入门react笔记(八)-redux的使用和项目搭建

一个更好用的文档 添加链接描述 箭头函数的简化 //简化前 function countIncreAction(data) {return {type:"INCREMENT",data} } //简化后 const countIncreAction data>({type:"INCREMENT",data })react UI组件库相关资料 组件库连接和推荐 antd组…

Python 多线程大批量处理文件小程序

说明 平时偶尔需要进行重复性的对文件进行重命名、格式转化等。假设以文件复制功能作为目标&#xff0c;设计一个小程序使用多线程对文件进行批量复制。&#xff08;其实以后主要目标是针对Realsense的raw文件进行批量的转化&#xff0c;并借助多线程加速&#xff09; 代码 i…

uv 必备的工具 ps ai 全家桶合集

非常稀有的资源 &#xff0c;必应搜索 易品资源yipinziyuan 可以找到

sqllab第二十关通关笔记

知识点&#xff1a; cookie注入 可以进行url解析错误注入传参位置 get请求post请求cookie传参 输入admin admin进行登录&#xff0c;抓取当前数据包 通过放包发现是一个302跳转的响应包&#xff0c;页面只有一个 I Love Cookies&#xff1b;没什么信息 通过点击页面上方的按钮…

若你有才能,最好能遇上识才之人,高俅发迹的故事很好诠释了千里马与伯乐的关系

若你有才能&#xff0c;最好能遇上识才之人&#xff0c;高俅发迹的故事很好诠释了千里马与伯乐的关系 其实&#xff0c;“千里马”和“伯乐”都是中国古代传说里的角色。伯乐是古代一个善于相马&#xff08;识别马的好坏&#xff09;的人&#xff0c;而“千里马”则是指一匹能跑…

数通-路由技术基础介绍

自治系统——AS&#xff1b;LAN和广播域&#xff1b;CN-2——精品线路 路由器互联网段为同网段&#xff08;不同网段会造成三层不通&#xff0c;非直连则不会产生直连路由&#xff09; 路由选路&#xff0c;一个路由器的各个接口不能配置相同网段。 IP路由表&#xff1a;例&…

前端学习之css样式 背景样式、字体样式、列表样式、边框样式、内外边距元素属性的转换

背景样式 html文件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>背景样式</title><link rel"stylesheet" href"../css/3.1背景样式.css"> </head> <bo…

华为云APIG跨域资源共享方案

## 浏览器的同源策略 浏览器的同源策略是一种安全机制&#xff0c;旨在保护用户的信息安全和隐私。它限制了一个网页的脚本只能与来自同一源的资源进行交互&#xff0c;即同源策略要求页面中加载的所有资源&#xff08;包括脚本、样式表、图片等&#xff09;必须来自相同的**域…

python之万花尺

1、使用模块 import sys, random, argparse import numpy as np import math import turtle import random from PIL import Image from datetime import datetime from math import gcd 依次使用pip下载即可 2、代码 import sys, random, argparse import numpy as np imp…