Go语言数据结构-单链表入门
链表相关概念
首先链表是一种线性表,是一个有序的序列。这意味着表中的各个表项是相继排序的,且每两项都有直接前驱和直接后继的关系,也就是说,线性表存在唯一的第一表项和唯一的最后表项。
L
=
(
a
1
,
…
,
a
i
,
a
i
+
1
,
…
,
a
n
)
L = (a_1,\dots,a_i,a_{i+1},\dots,a_n)
L=(a1,…,ai,ai+1,…,an)
单链表是一种最简单的链表表示,也叫作线性链表。它的表项主要由储存数据和储存节点组成,储存节点用于实现与其他表项的逻辑关系。
单链表的特点是长度可以很方便地进行扩充。单链表的数据元素的顺序与各节点的物理顺序可能不一致,它们是通过节点指针相联系的。
Go语言单链表实现
在Go语言中单链表使用一个结构体来实现。
对于一个存储数据类型为type
的数据的单链表typeNode
节点结构体可以这样声明:
type typeNode struct {
data type // 存储的数据
next *typeNode // 指向下一个节点的指针
}
单链表的创建与操作都需要辅助节点变量来完成。创建时需要一个头结点head
,操作时需要辅助节点temp
。所有的方法编写也是针对头结点head
指针编写的。
插入
// temp是一个辅助节点,表示Node_i
newNode.next = temp.next
temp.next = newNode
length++
删除
// temp是一个辅助节点,表示Node_i
temp.next = temp.next.next
length--
单链表实例
- 创建一个存储水浒英雄的单链表,有英雄名称
name string
和英雄编号no int
。 - 可以实现链表元素的添加与删除
- 另外想办法可以得到按编号排序好的英雄单链表
代码参考
package main
import (
"fmt"
)
// 定义节点
type heroNode struct {
no int
name string
next *heroNode // nextNode
}
var length = 0 // 用全局变量来记录链表节点数,注意这样只能创建一个链表
// 链表插入节点
// 从最后插入
func (head *heroNode) insert(newHeroNode *heroNode) {
// 1.创建辅助节点
temp := head
// 2.先定位到最后的节点
for {
if temp.next == nil { // 表示找到最后
break
}
temp = temp.next // 不断的找向下一个节点
}
// 3.插入节点
temp.next = newHeroNode
length++ // 长度增加
}
// 排序插入(按照编号从小到大排序)
func (head *heroNode) sortInsert(newHeroNode *heroNode) {
// 1.创建辅助节点和标记
temp := head
flag := false
// 2.先定位要插入的排序位置
for {
if temp.next == nil {
break
} else if temp.next.no > newHeroNode.no {
break
} else if temp.next.no == newHeroNode.no {
flag = true
}
temp = temp.next
}
// 3.插入第一个节点
if !flag { // 确保此编号的元素并不在链表中
newHeroNode.next = temp.next
temp.next = newHeroNode
length++
}
}
// 获取长度
func (head *heroNode) Length() int {
return length
}
// 删除节点
func (head *heroNode) delete(heroNo int) {
// 1.创建辅助节点和标记
temp := head
flag := false
// 2.先定位要插入的排序位置
for {
if temp.next == nil {
break
} else if temp.next.no == heroNo {
flag = true
break
}
temp = temp.next
}
// 3.节点删除
if flag { // 表示找到了
temp.next = temp.next.next // 删除节点
length--
}
}
// 清楚所有节点
func (head *heroNode) clear() {
head.next = nil
length = 0 // 长度归零
}
// 显示链表的所有节点
func (head *heroNode) printNode() {
// 1.创建辅助节点
temp := head
// 2.遍历整个链表
if temp.next == nil { // 不能是空链表
fmt.Println("...")
return
}
temp = temp.next
for {
// 3.打印输出
fmt.Printf("[%d,%s]", temp.no, temp.name)
temp = temp.next
if temp == nil { // 最后节点
fmt.Println()
break
}
}
}
// -----------------------------------------main----------------------------------------
func main() {
// 1.构建头结点
head := &heroNode{}
// 2.添加新节点
head.insert(&heroNode{1, "宋江", nil})
head.insert(&heroNode{2, "卢俊义", nil})
head.insert(&heroNode{3, "吴用", nil})
head.insert(&heroNode{4, "公孙胜", nil})
println(head.Length(), "----------------------") // 4
head.printNode() // [1,宋江][2,卢俊义][3,吴用][4,公孙胜]
// 3.删除节点
head.delete(3)
println(head.Length(), "----------------------") // 3
head.printNode() // [1,宋江][2,卢俊义][4,公孙胜]
// 4.清除节点
head.clear()
println(head.Length(), "----------------------") // 0
head.printNode() // ...
// 5.有序插入节点
head.sortInsert(&heroNode{4, "公孙胜", nil})
head.sortInsert(&heroNode{2, "卢俊义", nil})
head.sortInsert(&heroNode{3, "吴用", nil})
head.sortInsert(&heroNode{7, "秦明", nil})
head.sortInsert(&heroNode{1, "宋江", nil})
head.sortInsert(&heroNode{6, "林冲", nil})
head.sortInsert(&heroNode{5, "关胜", nil})
head.sortInsert(&heroNode{8, "呼延灼", nil})
println(head.Length(), "----------------------") // 8
head.printNode() // [1,宋江][2,卢俊义][3,吴用][4,公孙胜][5,关胜][6,林冲][7,秦明][8,呼延灼]
}