Golang中指针可以直接操作内存地址,这一特性非常适合用来实现链表这种需要节点间相互引用的数据结构。链表的核心是由多个节点组成,每个节点包含自身存储的数据和指向下一个节点的指针,通过指针的串联就能形成完整的链表结构。

链表节点的定义
首先需要定义链表的节点结构体,节点中需要包含存储数据的字段和指向下一个节点的指针字段。这里以存储整型数据的单链表为例,节点定义如下:
package main
import "fmt"
// 定义链表节点结构体
type ListNode struct {
Val int // 节点存储的数据
Next *ListNode // 指向下一个节点的指针
}
结构体中的Next字段是指向ListNode类型的指针,用来关联下一个节点,当没有下一个节点时,该指针的值为nil。
链表的基础操作实现
创建链表
可以通过手动创建节点并串联指针的方式构建一个简单的链表,示例代码如下:
// 创建链表
func createLinkedList() *ListNode {
// 创建三个节点
node1 := &ListNode{Val: 1}
node2 := &ListNode{Val: 2}
node3 := &ListNode{Val: 3}
// 用指针串联节点
node1.Next = node2
node2.Next = node3
// 返回头节点
return node1
}
遍历链表
遍历链表需要从头节点开始,依次通过指针访问下一个节点,直到遇到nil为止,实现代码如下:
// 遍历链表并打印所有节点值
func traverseLinkedList(head *ListNode) {
current := head
for current != nil {
fmt.Print(current.Val, " ")
current = current.Next
}
fmt.Println()
}
插入节点
链表插入节点分为头部插入、尾部插入和中间插入,这里以头部插入为例,实现代码如下:
// 头部插入节点
func insertAtHead(head *ListNode, val int) *ListNode {
// 创建新节点
newNode := &ListNode{Val: val}
// 新节点的Next指向原来的头节点
newNode.Next = head
// 返回新的头节点
return newNode
}
删除节点
删除节点需要找到目标节点的前一个节点,修改前一个节点的Next指针跳过目标节点,这里以删除第一个值为指定值的节点为例:
// 删除第一个值为指定值的节点
func deleteNode(head *ListNode, val int) *ListNode {
// 如果头节点就是要删除的节点
if head != nil && head.Val == val {
return head.Next
}
current := head
// 遍历找到目标节点的前一个节点
for current != nil && current.Next != nil {
if current.Next.Val == val {
current.Next = current.Next.Next
break
}
current = current.Next
}
return head
}
完整运行示例
将上面的方法整合起来,运行完整的测试代码:
func main() {
// 创建链表
head := createLinkedList()
fmt.Print("初始链表:")
traverseLinkedList(head) // 输出:1 2 3
// 头部插入节点
head = insertAtHead(head, 0)
fmt.Print("头部插入后:")
traverseLinkedList(head) // 输出:0 1 2 3
// 删除节点
head = deleteNode(head, 2)
fmt.Print("删除值为2的节点后:")
traverseLinkedList(head) // 输出:0 1 3
}
注意事项
- Golang的指针不能进行偏移运算,只能进行赋值和取值操作,所以实现链表时不需要处理指针偏移的问题。
- 操作链表时要注意处理
nil指针的情况,避免出现空指针异常。 - 如果链表节点需要存储复杂类型的数据,只需要修改结构体中的
Val字段类型即可,指针部分的逻辑不需要改动。