当前位置: 首页 > news >正文

数据结构【Golang实现】(四)——双向循环链表

目录

  • 0. 定义节点
  • 1. IsEmpty()
  • 2. Length()
  • 3. AddFromHead()
  • 4. AddFromTail()
  • 5. Insert()
  • 6. DeleteHead()
  • 7. DeleteTail()
  • 8. Remove()
  • 9. RemoveByValue()
  • 10. Contain()
  • 11. Traverse()

0. 定义节点

type DLNode struct {Data       anyPrev, Next *DLNode
}// DoublyLoopLinkedList 双向循环链表
type DoublyLoopLinkedList struct {headNode *DLNode
}

1. IsEmpty()

// IsEmpty 判断链表是否为空
func (l *DoublyLoopLinkedList) IsEmpty() bool {if l.headNode == nil {return true}return false
}

2. Length()

// Length 获取链表长度
func (l *DoublyLoopLinkedList) Length() int {if l.IsEmpty() {return 0}currentNode := l.headNodecount := 1for currentNode.Next != l.headNode {count++currentNode = currentNode.Next}return count
}

3. AddFromHead()

// AddFromHead 从双向循环链表头部增加节点
func (l *DoublyLoopLinkedList) AddFromHead(data any) {node := &DLNode{Data: data}if l.IsEmpty() {l.headNode = nodereturn}currentNode := l.headNodefor currentNode.Next != l.headNode { // 遍历到尾结点currentNode = currentNode.Next}currentNode.Next = nodel.headNode.Prev = nodenode.Prev = currentNodenode.Next = l.headNodel.headNode = node
}

4. AddFromTail()

// AddFromTail  从双向循环链表尾部增加节点
func (l *DoublyLoopLinkedList) AddFromTail(data any) {node := &DLNode{Data: data}if l.IsEmpty() {l.headNode = nodereturn}currentNode := l.headNodefor currentNode != l.headNode { // 遍历到尾结点currentNode = currentNode.Next}currentNode.Next = nodel.headNode.Prev = nodenode.Prev = currentNodenode.Next = l.headNode
}

5. Insert()

// Insert  从双向循环链表指定位置增加节点 下标从0开始
func (l *DoublyLoopLinkedList) Insert(position int, data any) {if position <= 0 {l.AddFromHead(data)return} else if position >= l.Length()-1 {l.AddFromTail(data)return} else {node := &DLNode{Data: data}count := 0currentNode := l.headNodefor count != position {count++currentNode = currentNode.Next}node.Next = currentNodenode.Prev = currentNode.PrevcurrentNode.Prev.Next = nodecurrentNode.Prev = node}
}

6. DeleteHead()

// DeleteHead 删除链表头结点
func (l *DoublyLoopLinkedList) DeleteHead() {if l.IsEmpty() {fmt.Println("Doubly Linked List is Empty")return}currentNode := l.headNodeif currentNode.Next == l.headNode { // 只有一个节点的情况l.headNode = nilreturn} else {for currentNode.Next != l.headNode { // 遍历到倒数第一个节点currentNode = currentNode.Next}currentNode.Next = l.headNode.Nextl.headNode.Next.Prev = currentNodel.headNode = l.headNode.Next}
}

7. DeleteTail()

// DeleteTail 删除链表尾结点
func (l *DoublyLoopLinkedList) DeleteTail() {if l.IsEmpty() {fmt.Println("Doubly Linked List is Empty")return}currentNode := l.headNodeif currentNode.Next == l.headNode { // 只有一个节点的情况l.headNode = nilreturn} else {for currentNode.Next != l.headNode {currentNode = currentNode.Next}currentNode.Prev.Next = l.headNodel.headNode.Prev = currentNode.Prev}
}

8. Remove()

// Remove 删除链表指定位置结点
func (l *DoublyLoopLinkedList) Remove(position int) {if position <= 0 {l.DeleteHead()return} else if position >= l.Length()-1 {l.DeleteTail()return} else {count := 0currentNode := l.headNodefor count != position {count++currentNode = currentNode.Next}currentNode.Prev.Next = currentNode.NextcurrentNode.Next.Prev = currentNode.Prev}
}

9. RemoveByValue()

// RemoveByValue 删除链表指定值的节点
func (l *DoublyLoopLinkedList) RemoveByValue(data any) {if l.IsEmpty() {fmt.Println("Doubly Linked List is Empty")return}currentNode := l.headNodeif currentNode.Data == data { // 比较头结点l.DeleteHead()return}for currentNode.Next != l.headNode { // 这里是跳过了头结点的if currentNode.Next.Data == data {currentNode.Next.Prev.Next = currentNode.Next.NextcurrentNode.Next.Next.Prev = currentNode.Next.Prevreturn} else {currentNode = currentNode.Next}}
}

10. Contain()

// Contain 查询双向循环链表是否包含某个节点
func (l *DoublyLoopLinkedList) Contain(data any) bool {if l.IsEmpty() {return false}currentNode := l.headNodefor currentNode.Next != l.headNode {if currentNode.Data == data {return true} else {currentNode = currentNode.Next}}if currentNode.Data == data {return true}return false
}

11. Traverse()

// Traverse 遍历双向循环链表
func (l *DoublyLoopLinkedList) Traverse() {if l.IsEmpty() {fmt.Println("Doubly Linked List is Empty")return}currentNode := l.headNodefor currentNode.Next != l.headNode {fmt.Printf("%v -> ", currentNode.Data)currentNode = currentNode.Next}fmt.Printf("%v\n", currentNode.Data)
}

相关文章:

数据结构【Golang实现】(四)——双向循环链表

目录0. 定义节点1. IsEmpty()2. Length()3. AddFromHead()4. AddFromTail()5. Insert()6. DeleteHead()7. DeleteTail()8. Remove()9. RemoveByValue()10. Contain()11. Traverse()0. 定义节点 type DLNode struct {Data anyPrev, Next *DLNode }// DoublyLoopLinkedLis…...

【Redis】高可用架构之哨兵模式 - Sentinel

Redis 高可用架构之哨兵模式 - Sentinel1. 前言2. Redis Sentinel 哨兵集群搭建2.1 一主两从2.2 三个哨兵3. Redis Sentinel 原理剖析3.1 什么哨兵模式3.2 哨兵机制的主要任务3.2.1 监控&#xff08;1&#xff09;每1s发送一次 PING 命令&#xff08;2&#xff09;PING 命令的回…...

图片的美白与美化

博主简介 博主是一名大二学生&#xff0c;主攻人工智能研究。感谢让我们在CSDN相遇&#xff0c;博主致力于在这里分享关于人工智能&#xff0c;c&#xff0c;Python&#xff0c;爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主&#xff0c;博主会继续更新的&#xff0c…...

面试官:关于CPU你了解多少?

CPU是如何执行程序的&#xff1f; 程序执行的基本过程 第一步&#xff0c;CPU 读取「程序计数器」的值&#xff0c;这个值是指令的内存地址&#xff0c;然后 CPU 的「控制单元」操作「地址总线」指定需要访问的内存地址&#xff0c;接着通知内存设备准备数据&#xff0c;数据准…...

UI自动化测试-Selenium的使用

文章目录 1. 环境搭建1.1 入门示例1.2 元素操作常用方法1.3 浏览器操作常用方法1.4 获取元素信息常用方法1.5 鼠标操作常用方法1.6 键盘操作常用方法1.7 下拉选择框操作2. 元素定位2.1 id定位2.2 name定位2.3 class_name定位2.4 tag_name定位2.5 link_text定位2.6 partail_link…...

嵌入式学习笔记——STM32的USART相关寄存器介绍及其配置

文章目录前言USART的相关寄存器介绍状态寄存器&#xff1a;USARTX->SR具体位代表的含义实际代码数据寄存器 USARTX->DR波特率寄存器 USARTX->BRR控制寄存器 (USART_CR)控制寄存器1&#xff08;USART_CR1&#xff09;控制寄存器2&#xff08;USART_CR2&#xff09;GPIO…...

Android setContentView流程分析(一)

对于做Android App的小伙伴来说setContentView这个方法再熟悉不过了&#xff0c;那么有多少小伙伴知道它的调用到底做了多少事情呢&#xff1f;下面就让我们来看看它背后的故事吧&#xff1f; setContentView()方法将分为两节来讲&#xff1a;   第一节&#xff1a;如何获取De…...

doris数据库操作数字遇到的问题

关于doris数据库Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库&#xff0c;以极速易用的特点被人们所熟知&#xff0c;仅需亚秒级响应时间即可返回海量数据下的查询结果&#xff0c;不仅可以支持高并发的点查询场景&#xff0c;也能支持高吞吐的复杂分析场景。…...

3.13文件的IO操作

一.文件1.定义文件一般指的是存储在硬盘上的普通文件形如:txt.jpg.mp4,rar等这些文件在计算机中,文件可能是一个广义的概念,不仅可以包含普通文件,还可以包含目录(也就是文件夹.把目录称为目录文件)在操作系统中,还会用文件来描述一些其他的硬件设备或者软件资源比如网卡,显示器…...

ffmpeg使用

1 下载FFmpeg安装 官网地址&#xff1a;https://www.ffmpeg.org/download.html#build-windows 进入网址&#xff0c;点击下面红框部分 点击下面范围进行下载&#xff0c;下载速度有点慢&#xff0c;等等吧&#xff01; 下载成功后&#xff0c;解压后&#xff0c;复制bin的路…...

spark中的并行度(分区数)/分区器如何确定

源头RDD有自己的分区计算逻辑&#xff0c;一般没有分区器,并行度是根据分区算法自动计算的&#xff0c;RDD的compute函数中记录了数据如何而来&#xff0c;如何分区的hadoopRDD&#xff0c;根据XxxinputFormat.getInputSplits()来决定&#xff0c;比如默认的TextInputFormat将文…...

00后女生“云摆摊”两周赚1.5万,实体店转战线上真的能赚钱吗?

最近&#xff0c;山东临沂的00后女生利用小程序在线上“云摆摊”卖水果&#xff0c;两周赚1.5万&#xff0c;引发网友热议。不少人发出质疑的声音&#xff1a;年轻人不要有稳定的工作不做&#xff0c;去摆摊&#xff1b;网上开店成本低&#xff0c;开实体店结果就难说了&#x…...

华为OD机试题 - 最优资源分配(JavaScript)| 机考必刷

更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:最优资源分配题目输入输出描述备注示例一输入输出说明示例二输入…...

利用python判断字符串是否为回文

1 问题 如何用python判断字符串是否为回文。 2 方法 用两个变量left&#xff0c;right模仿指针&#xff08;一个指向第一个字符&#xff0c;一个指向最后一个字符&#xff09;&#xff0c;每比对成功一次&#xff0c;left向右移动一位&#xff0c;right向左移动一位&#xff0c…...

GDB 调用之ptype、set variable

今天在公司的时候&#xff0c;排查一个问题&#xff0c;创建l3 lif 失败&#xff0c;查看各种日志发现是用key去创建的 lif失败了&#xff0c;日志里指示key为空&#xff0c;导致的创建失败。原因为一个结构体比基线的多了一些东西&#xff0c;导致版本不对&#xff0c;既而计算…...

并发编程---阻塞队列(五)

阻塞队列一 阻塞队列1.1.阻塞队列概念1.2.阻塞队列API案例1.2.1. ArrayBlockingQueue1.2.1.1.抛出异常1.2.1.2.返回布尔1.2.1.3.阻塞1.2.1.4.超时1.2.2.SynchronousQueue二 阻塞队列应用---生产者消费者2.1.传统模式案例代码结果案例问题---防止虚假唤醒2.2.⽣产者消费者防⽌虚…...

本科课程【计算机组成原理】实验1 - 输出ABCD程序的生成

大家好,我是【1+1=王】, 热爱java的计算机(人工智能)渣硕研究生在读。 如果你也对java、人工智能等技术感兴趣,欢迎关注,抱团交流进大厂!!! Good better best, never let it rest, until good is better, and better best. 近期会把自己本科阶段的一些课程设计、实验报…...

Java并发编程(2) —— 线程创建的方式与原理

一、Java线程创建的三种方式 1. 继承Thread类并重写run()方法 ///方法一&#xff1a;使用匿名内部类重写Thread的run()方法Thread t1 new Thread() {Overridepublic void run() {try {sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}log.debug("…...

你写的js性能有多差你知道吗 | js性能优化

性能的计算⽅式 确认⾃⼰需要关注的指标 常⻅的指标有&#xff1a; ⻚⾯总加载时间 load⾸屏时间⽩屏时间 代码 尝试⽤⼀个指令, 挂载在重要元素上, 当此元素inserted就上报 各个属性所代表的含义 connectStart, connectEnd 分别代表TCP建⽴连接和连接成功的时间节点。如果浏…...

线程的状态、状态之间的相互转换

目录 一、线程的状态 1. NEW 2. TERMINATED 3. RUNNABLE 4. TIMED_WAITING 5. BLOCKED 6. WAITING 二、线程状态转换 1. 线程状态转换简图 一、线程的状态 线程的状态一共有 6 种&#xff1a; NEW&#xff1a;安排了工作&#xff0c;还未开始行动&#xff08;调用 st…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

k8s从入门到放弃之HPA控制器

k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率&#xff08;或其他自定义指标&#xff09;来调整这些对象的规模&#xff0c;从而帮助应用程序在负…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例

目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码&#xff1a;冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...

leetcode73-矩阵置零

leetcode 73 思路 记录 0 元素的位置&#xff1a;遍历整个矩阵&#xff0c;找出所有值为 0 的元素&#xff0c;并将它们的坐标记录在数组zeroPosition中置零操作&#xff1a;遍历记录的所有 0 元素位置&#xff0c;将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...

MeshGPT 笔记

[2311.15475] MeshGPT: Generating Triangle Meshes with Decoder-Only Transformers https://library.scholarcy.com/try 真正意义上的AI生成三维模型MESHGPT来袭&#xff01;_哔哩哔哩_bilibili GitHub - lucidrains/meshgpt-pytorch: Implementation of MeshGPT, SOTA Me…...