Golang 实现链表类型及相关操作
最近工作用到了 golang,并且需要我实现一个链表的类型来作为生产者-消费者的“仓库”。由于自己是边用边学,就先写一个小 demo 熟悉一下,在里面实现了一个链表的类型,并包括了遍历以及增、查、删等操作,代码如下:
package main
import "fmt"
type StuInfo struct {
id, name string
age int
address string
}
type Node struct {
*StuInfo
next *Node
}
type List struct {
head, tail *Node
cnt int
}
func NewStu(id, name string, age int, address string) *StuInfo {
stu := &StuInfo{
id: id,
name: name,
age: age,
address: address,
}
return stu
}
func NewNode(stu *StuInfo) *Node {
return &Node{
StuInfo: stu,
next: nil,
}
}
// 尾插法
func (li *List) AddTail(newNode *Node) {
if li.head == nil && li.tail == nil {
// 向空链表插入一个新节点
li.head = newNode
li.tail = newNode
li.cnt += 1
return
}
li.tail.next = newNode
li.tail = newNode
li.cnt += 1
}
// 根据 id 查找节点
func (li *List) Search(id string) (result *Node, ret bool) {
if li.cnt == 0 {
fmt.Println("list is empty!")
return nil, false
}
result = li.head
ret = false
for result != li.tail {
if result.id == id {
ret = true
break
} else {
result = result.next
}
}
if !ret {
// 遍历链表未找到目标节点
return nil, ret
}
// 找到了目标节点
return result, ret
}
// 根据 id 删除一个节点
func (li *List) Delete(id string) (ret bool) {
if li.cnt == 0 {
fmt.Println("list is empty!")
return false
}
if li.head.id == id {
// 如果要删除的节点是头结点
li.cnt -= 1
if li.head.next == nil {
// 如果只有一个节点,并且刚好被删除
li.head = nil
li.tail = nil
return true
}
// 否则直接将头节点后移
li.head = li.head.next
return true
}
// 若链表不为空且要删除的点不是头结点,就进行查找并删除
pre := li.head
cur := li.head.next
for cur != nil {
if cur.id == id {
// 找到目标节点,删除
pre.next = cur.next
if cur == li.tail {
// 如果目标节点是尾结点
li.tail = pre
}
cur.next = nil
cur = nil
li.cnt -= 1
return true
}
pre = cur
cur = cur.next
}
// 目标节点不在链表中
fmt.Printf("%s is not our student\n", id)
return false
}
// 遍历链表
func (li *List) Traversal() {
if li.cnt == 0 {
fmt.Println("list is empty!")
return
}
fmt.Println("now list size is", li.cnt)
cur := li.head
for cur != nil {
fmt.Printf("stu: %s\t%s\t%d\t%s\n", cur.id, cur.name, cur.age, cur.address)
cur = cur.next
}
}
func listTest() {
l1 := *new(List)
stu1 := NewStu("22001", "LingHuChong", 23, "ShanXi")
stu2 := NewStu("22002", "HuangRong", 19, "HuBei")
stu3 := NewStu("22003", "XiaoFeng", 27, "BeiJing")
node1 := NewNode(stu1)
node2 := NewNode(stu2)
node3 := NewNode(stu3)
l1.Traversal()
l1.Delete("22001")
l1.AddTail(node1)
l1.AddTail(node2)
l1.AddTail(node3)
l1.Traversal()
target := "22001"
s, ret := l1.Search(target)
if !ret {
fmt.Printf("didn't find %s\n", target)
} else {
fmt.Printf("found %s: %s\t%d\t%s\n", target, s.name, s.age, s.address)
}
if l1.Delete(target) {
fmt.Println("deleted", target)
}
l1.Traversal()
if l1.Delete("22002") {
fmt.Println("deleted 22002")
}
l1.Traversal()
if l1.Delete("22003") {
fmt.Println("deleted 22003")
}
l1.Traversal()
}
func main() {
listTest()
}
运行结果如下:
写在最后,实际上不需要链表,利用 golang 内置的切片类型,完全可以满足一般的需求