Go语言单向链表实现:结构体定义、增删改查操作详解

南乔
南乔
发布时间:2026-10-16| 5人浏览过
原创

在Go语言中,链表是一种重要的动态数据结构,通过指针将非连续的内存块串联起来。本文将深入解析如何利用struct结构体和指针构建单向链表,详细演示节点的初始化、尾部追加、头部插入、指定位置插入以及删除节点等完整操作逻辑。

链表基础与Go实现原理

链表是由一系列结点(Node)组成的非线性存储结构。每个结点包含两部分:

  1. 数据域:用于存储具体数据(如学生姓名、成绩等)。
  2. 指针域:存储指向下一个结点的内存地址,用于链接前后结点。

与数组不同,链表不需要预先分配连续内存空间,适合数据量动态变化的场景。但在Go语言中,由于存在垃圾回收机制和对象开销,链表的内存利用率需结合实际情况考量。单项链表的数据只能单向遍历,从头部至尾部。

第1步:使用Struct定义链表节点

Go语言没有原生链表类型,需通过自定义struct配合指针来实现。以下是定义单向链表节点的标准方式。

1. 结构体定义方法

在Go中,可以使用 var 或 & 运算符创建结构体实例及指针。对于链表,通常需要持有指向下一个节点的指针字段。

// 定义结构体
var stu Student
// 创建指针并初始化
var stu *Student = new(Student)
var stu *Student = &Student{}

// 属性访问:直接使用 stu.Name 或通过 (*stu).Name

2. 构建单链表结构

以存储学生信息为例,为 Student 结构体添加一个指向自身的指针字段 next,从而形成链表连接关系。

type Student struct {
	Name  string
	Age   int
	Score float32
	next  *Student // 关键:指向下一个同类型结构体的指针
}

第2步:创建节点并遍历链表

在内存中手动创建几个节点,并通过赋值指针将它们串联起来,最后编写遍历函数输出所有数据。这是理解链表逻辑的基础步骤。

1. 手动串联节点

分别定义头部节点和其他中间节点,通过 =& 获取地址并赋值给前一个节点的 next 字段。

2. 遍历输出

利用循环判断当前节点指针是否为 nil,若不空则打印数据并移动指针至下一节点。

package main

import "fmt"

type Student struct {
	Name  string
	Age   int
	Score float32
	next  *Student
}

func main() {
	// 创建第一个节点 (Head)
	var head Student
	head.Name = "张三"
	head.Age = 28
	head.Score = 88

	// 创建第二个节点
	var stu1 Student
	stu1.Name = "李四"
	stu1.Age = 25
	stu1.Score = 100
	head.next = &stu1 // Head 指向 stu1

	// 创建第三个节点
	var stu2 Student
	stu2.Name = "王五"
	stu2.Age = 18
	stu2.Score = 60
	stu1.next = &stu2 // stu1 指向 stu2

	// 调用遍历函数
	Req(&head)
}

// 遍历函数
func Req(tmp *Student) {
	for tmp != nil { // 只要不为空指针就继续
		fmt.Println(*tmp)
		tmp = tmp.next // 指针后移
	}
}

// 运行结果示例:
// {张三 28 88 0xc000...}
// {李四 25 100 0xc000...}
// {王五 18 60 <nil>}

第3步:尾部追加新节点

当链表长度不确定时,手动逐个创建节点效率低下。通常需要通过循环或函数动态向链表末尾添加新节点。

方法一:直接在Main中维护尾指针

声明一个 tail 变量始终指向链表的最后一个节点。每次创建新节点时,将 tail.next 指向新节点,然后更新 tail 为新节点本身。

方法二:封装TailInsert函数

将追加逻辑封装,简化主流程。注意:main中的局部变量地址作为参数传递时,若在函数内重新赋值指针改变的是函数内的拷贝,因此需要正确理解传参行为或使用指针的指针。

func TailInsert(tail *Student) {
	for i := 0; i < 10; i++ {
		var stu Student = Student{
			Name:  fmt.Sprintf("stu%d", i),
			Age:   rand.Intn(100),
			Score: rand.Float32() * 100,
		}
		// 将当前尾节点的 next 指向新生成的节点
		tail.next = &stu
		// 更新 tail 指针,使其指向这个新加入的节点
		tail = &stu
	}
}

注:上述代码片段若直接放入main执行需注意变量的生命周期和作用域,实际工程中常配合头指针返回或双重指针处理。

第4步:头部插入节点

在链表头部插入节点时,新节点将成为新的起点,原链表的第一个节点变为新节点的下一个节点。

方法一:通过返回值更新头指针

函数接收当前头指针,不断创建新节点并将其 next 指向旧的头,最后返回最新的新头指针。外部接收返回值即可。

方法二:使用二级指针(Pointer to Pointer)

传入 **Student,直接在函数内部修改外部头指针的指向。这种方法在处理链表头变动时非常经典且高效。

func HeadInsert(p **Student) {
	for i := 0; i < 10; i++ {
		var stu = Student{
			Name:  fmt.Sprintf("stu%d", i),
			Age:   rand.Intn(100),
			Score: rand.Float32() * 100,
		}
		// 新节点的 next 指向当前 p 所指的节点
		stu.next = *p
		// 让 p 指向新节点 (即修改了外部传入的头指针)
		*p = &stu
	}
}

// 调用示例
var head *Student = &Student{Name: "Head"}
HeadInsert(&head)

第5步:指定位置插入与删除节点

除了首尾,经常需要在链表的特定位置进行插入或删除操作。这涉及对“前驱节点”和“后继节点”指针的重定向。

1. 指定节点后插入(Add Node)

寻找目标节点(例如 Name == "stu6"),将其 next 保存到新节点的 next 中,然后将目标节点的 next 指向新节点。

func Add(p *Student, newNode *Student) {
	for p != nil {
		if p.Name == "stu6" {
			newNode.next = p.next // 1. 新节点接管原后继
			p.next = newNode      // 2. 原节点指向新节点
			break
		}
		p = p.next
	}
}

2. 删除指定节点

删除节点需要找到该节点的前驱节点。遍历过程中用 prev 记录当前节点的前一个状态。当发现目标节点时,将前驱节点的 next 直接跳过目标节点,指向目标的下一个节点。

func del(p *Student) {
	var prev *Student = p
	for p != nil {
		if p.Name == "target_name" {
			prev.next = p.next // 跳过当前节点
			break
		}
		prev = p
		p = p.next
	}
}

总结

掌握Go语言链表的核心在于理解指针的值传递特性与内存引用。若要在函数外同步头指针的变化,必须通过以下两种手段之一:

  1. 传递指针的地址:使用 **Student 类型的参数。
  2. 返回值机制:函数返回新的头指针,由调用者接收并重新赋值。

以上就是Go语言学习之链表的使用详解的详细内容,更多关于Go语言链表的操作与优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。