Go的数据结构与实现【LinkedList】

介绍

所谓链表(Linked List),就是按线性次序排列的一组数据节点。每个节点都是一个对象,它通过一个引用指向对应的数据元素,同时还通过一个引用next指向下一节点。

实现

逻辑方法

我们定义链表的结构体:

// LinkedList the linked list struct
type LinkedList struct {sync.RWMutexhead *Nodesize int
}// Node a single node that composes the list
type Node struct {content Tnext    *Node
}

其中包含头节点和链表长度,在这里我们主要实现以下方法:

  • Add:添加一个元素到链表末尾
  • Insert:向链表指定位置插入元素
  • RemoveAt:移除指定索引位置的元素
  • IndexOf:取指定索引位置的元素
  • IsEmpty:判断链表是否为空
  • Size:获取链表长度
  • Traverse:遍历链表并输出

首先是Add方法,判断链表头节点是否为空,若空则设置头节点为插入的元素,若非空,找到链表末尾节点,再插入元素。

// Add adds t to the end of the linked list
func (l *LinkedList) Add(t T) {l.Lock()defer l.Unlock()node := NewNode(t)if l.head == nil {l.head = node} else {last := l.headfor {if last.next == nil {break}last = last.next}last.next = node}l.size++
}

Insert方法,注意判断索引位置是否合法,再插入指定位置。

// Insert adds t at position pos
func (l *LinkedList) Insert(t T, pos int) error {l.Lock()defer l.Unlock()// validate positionif pos < 0 || pos > l.size {return fmt.Errorf("insert position must be larger than 0 and smaller than linked list size")}node := NewNode(t)if pos == 0 {node.next = l.headl.head = nodereturn nil}head := l.headidx := 0for idx < pos-2 {idx++head = head.next}node.next = head.nexthead.next = nodel.size++return nil
}

RemoveAt方法与之类似,判断索引位置是否合法再移除。

// RemoveAt removes a node at position pos
func (l *LinkedList) RemoveAt(pos int) (*T, error) {l.Lock()defer l.Unlock()// validate positionif pos < 0 || pos > l.size {return nil, fmt.Errorf("insert position must be larger than 0 and smaller than linked list size")}head := l.headidx := 0for idx < pos-1 {idx++head = head.next}next := head.nexthead.next = next.nextl.size--return &next.content, nil
}

剩下的方法直接取相应数据即可。

// IndexOf returns the position of the t
func (l *LinkedList) IndexOf(t T) int {l.RLock()defer l.RUnlock()head := l.headidx := 0for {if head.content == t {return idx}if head.next == nil {return -1}head = head.nextidx++}
}// IsEmpty returns true if the list is empty
func (l *LinkedList) IsEmpty() bool {l.RLock()defer l.RUnlock()return l.head == nil
}// Size returns the linked list size
func (l *LinkedList) Size() int {l.RLock()defer l.RUnlock()return l.size
}

遍历方法Traverse还会输出元素内容。

// Traverse traverses linked list
func (l *LinkedList) Traverse() {l.RLock()defer l.RUnlock()head := l.headfor {if head == nil {break}head.Print()head = head.next}fmt.Println()
}

单元测试

单元测试如下:

import "testing"var (t1 T = 1t2 T = 2t3 T = 3t4 T = 4
)func InitLinkedList() *LinkedList {list := NewLinkedList()list.head = NewNode(t1)list.head.next = NewNode(t2)list.head.next.next = NewNode(t3)list.size = 3return list
}func TestLinkedList_Add(t *testing.T) {linkedList := InitLinkedList()size := linkedList.Size()if size != 3 {t.Errorf("linked list size should be 3 but got %d", size)}linkedList.Add(4)size = linkedList.Size()if size != 4 {t.Errorf("linked list size should be 4 but got %d", size)}
}func TestLinkedList_Insert(t *testing.T) {linkedList := InitLinkedList()err := linkedList.Insert(t4, 1)if err != nil {t.Errorf("insert into linked list err %v", err)}idx1 := linkedList.IndexOf(t2)idx2 := linkedList.IndexOf(t4)if idx1 != 2 || idx2 != 1 {t.Errorf("linked list position is not expected.")}
}func TestLinkedList_RemoveAt(t *testing.T) {linkedList := InitLinkedList()ret, err := linkedList.RemoveAt(2)if err != nil {t.Errorf("linked list err %v", err)}if *ret != t3 {t.Errorf("removed item expect 3 but got %d", *ret)}size := linkedList.Size()if size != 2 {t.Errorf("linked list size should be 2 but got %d", size)}
}func TestLinkedList_IsEmpty(t *testing.T) {linkedList := InitLinkedList()empty := linkedList.IsEmpty()if empty {t.Errorf("linked list is not empty.")}linkedList = &LinkedList{}empty = linkedList.IsEmpty()if !empty {t.Errorf("linked list is empty.")}
}func TestLinkedList_Traverse(t *testing.T) {linkedList := InitLinkedList()linkedList.Traverse()
}

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

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

相关文章

VTD学习笔记(一)-启动vtd、基本界面和按钮

写在前面&#xff1a;真快啊&#xff0c;眨眼就毕业上班了&#xff0c;岗位也是做仿真&#xff0c;看来以后就是一直做仿真了&#xff0c;再见了定位~。公司使用的是vtd&#xff0c;看资料是一个很庞大的自动驾驶仿真软件&#xff0c;囊括了车辆动力学到传感器仿真&#xff0c;…

【WPF开发】上位机开发-串口收发

一、引言 在现代工业控制、嵌入式系统等领域&#xff0c;串口通信作为一种常见的通信方式&#xff0c;被广泛应用于各种场景。C#作为一门强大的编程语言&#xff0c;结合Windows Presentation Foundation&#xff08;WPF&#xff09;框架&#xff0c;可以轻松实现串口通信功能…

MMDet3d TR3D: RuntimeError: Error compiling objects for extension

项目&#xff1a; https://github.com/open-mmlab/mmdetection3d 问题复现&#xff1a; 步骤 运行python tools/test.py projects/TR3D/configs/tr3d_1xb16_scannet-3d-18class.py checkpoints/tr3d_1xb16_sunrgbd-3d-10class.pth后报错&#xff1a; File "/home/kyle…

vue2高级特性

1、vue父子组件如何通信 通过props和emit事件传递 // 父组件中<Child :data"data" dataChange"dataChangeHandle"></Child>...methods: {dataChangeHandle(data) {...do somthing} } // 子组件中export default {props: {data: {type: Objec…

C++ STL partition_copy 用法和实现

一&#xff1a;功能 对区间内的元素进行分组&#xff0c;将分组结果拷贝到给定序列中。 二&#xff1a;用法 #include <vector> #include <algorithm> #include <iostream>int main() {std::vector<int> data{2, 4, 6, 1, 3, 5};auto is_even [](in…

Python list comprehension (列表推导式 - 列表解析式 - 列表生成式)

Python list comprehension {列表推导式 - 列表解析式 - 列表生成式} 1. Python list comprehension (列表推导式 - 列表解析式 - 列表生成式)2. Example3. ExampleReferences Python 中的列表解析式并不是用来解决全新的问题&#xff0c;只是为解决已有问题提供新的语法。 列…

iPad型号数据解析:了解不同iPad型号的连接和扩展性能力

iPad是一款非常受欢迎的平板电脑&#xff0c;拥有多种型号和规格可供选择。在本篇文章中&#xff0c;我们将深入研究不同iPad型号的连接和扩展性能。数据源来自于挖数据平台&#xff0c;该平台提供了全面的iPad型号数据&#xff0c;共计1485个型号。 首先&#xff0c;让我们来…

【D3.js in Action 3 精译_020】2.6 用 D3 设置与修改元素样式 + 名人专访(Nadieh Bremer)+ 2.7 本章小结

当前内容所在位置 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可视化最佳实践&#xff08;下&#xff09;1.4 本章小结 第二章…

SpringBoot如何使用Kafka来优化接口请求的并发

在Spring Boot中使用 Kafka 来优化接口请求的并发&#xff0c;主要是通过将耗时的任务异步化到Kafka消息队列中来实现。这样&#xff0c;接口可以立即响应客户端&#xff0c;而不需要等待耗时任务完成。 在Spring Boot应用程序中调用Kafka通常涉及使用Spring Kafka库&#xff…

怎样用Java程序与数据库建立联系?

首先我们要了解一下JDBC&#xff0c;一个为Java程序与关系型数据库交互提供便利的API&#xff08;应用程序编程接口&#xff09;&#xff0c; 本期我们尝试用Java编程软件IDEA与MYSQL数据库建立联系。 首先我们在IDEA中穿件一个&#xff08;SQL&#xff09;&#xff0c;然后导…

系统编程--Linux下文件其他操作

这里写目录标题 文件存储理论补充dentry、inode 文件其他操作stat函数作用函数原型代码&#xff08;以获取文件大小为例&#xff09;补充&#xff08;获取文件类型&#xff09; lstat函数作用函数原型代码补充&#xff08;获取文件权限&#xff09;总结 tipslink函数作用简介函…

畅玩游戏新选择 :游戏本 Windows10 64位 专业版!

对于喜欢游戏竞技的玩家而言&#xff0c;选择一款合适的操作系统对于提升游戏体验至关重要。为了满足这一需求&#xff0c;系统之家小编将带来高性能的游戏本专用Win10操作系统。这一版本系统不仅注重游戏的稳定性&#xff0c;还针对玩家在游戏中可能遇到的超时检测和恢复&…

收银系统源码-千呼新零售收银视频介绍

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

JavaScript 模板字符串:让字符串拼接变得更优雅

在 JavaScript 开发中&#xff0c;字符串拼接是一个常见的需求。从简单的用户界面文本生成到复杂的动态数据格式化&#xff0c;字符串操作无处不在。传统的字符串拼接方法虽然功能强大&#xff0c;但往往显得冗长且难以阅读。为了解决这一问题&#xff0c;ES6&#xff08;ECMAS…

240718_使用Labelme制作自己的图像分割数据集

240718_使用Labelme制作自己的图像分割数据集 从目标检测入门的朋友们可能更熟悉的是LabelImg&#xff0c;这里要注意做好区分&#xff0c;LabelImg和Labelme不是一个东西&#xff0c;如下经典图&#xff1a; &#xff08;a&#xff09;图像分类&#xff08;目标检测&#xff…

跨平台webSocket模块设计技术解决方案

1. 概述 目标&#xff1a;设计并实现一个能够在多种操作系统上运行的WebSocket通讯模块&#xff0c;支持与前端浏览器和HTTPS服务端进行数据交换。技术栈&#xff1a;C11 &#xff0c;使用跨平台库如 Boost处理网络IO&#xff0c;使用 JSON 库如 nlohmann/json 解析消息。 2.…

Mysql深入讲解(索引、事务、锁机制)

一、MySQL索引 1、何为索引&#xff1f; MySQL中的索引是一种数据结构&#xff0c;用于加快对数据库表中数据的查询速度【查询速度提升】。它类似于书本目录&#xff0c;使得用户可以根据特定字段快速定位到所需的数据行&#xff0c;而无需扫描整个表。 2、索引分类 Hash索…

数据科学、数据分析、人工智能必备知识汇总-----主目录-----持续更新

本文相当于目录方便快速检索内容&#xff0c;没有实际内容&#xff0c;只做索引 新能源行业知识体系-------主目录-----持续更新https://blog.csdn.net/grd_java/article/details/140004020 目录 一、Excel二、常用数据分析思维方法三、Python基础和MySql四、Python爬虫 一、E…

怎样对 PostgreSQL 中的慢查询进行分析和优化?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 怎样对 PostgreSQL 中的慢查询进行分析和优化&#xff1f;一、理解慢查询的危害二、找出慢查询&#x…

Linux可视化工具-netdata之docker安装

版本要求 docker cli安装 docker pull netdata/netdata docker run -d --namenetdata \ --pidhost \ --networkhost \ -v netdataconfig:/etc/netdata \ -v netdatalib:/var/lib/netdata \ -v netdatacache:/var/cache/netdata \ -v /:/host/root:ro,rslave \ -v /etc/passwd…