Go 语言实现链表

链表相关实现的 Go 源文件是 linkedList.go,我们将分为五个部分来介绍。

linkedList.go 中的第一个代码段如下:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type Node struct {
  6. Value int
  7. Next *Node
  8. }
  9. var root = new(Node)

在这部分代码中,我们定义了用作链表节点的 Node 结构类型和保存链表第一个元素的全局变量 root,在代码的其他任何地方我们都能访问这个变量。

linkedList.go 的第二部分是如下的 Go 代码:

  1. func addNode(t *Node, v int) int {
  2. if root == nil {
  3. t = &Node{v, nil}
  4. root = t
  5. return 0
  6. }
  7. if v == t.Value {
  8. fmt.Println("Node already exists:", v)
  9. return -1
  10. }
  11. if t.Next == nil {
  12. t.Next = &Node{v, nil}
  13. return -2
  14. }
  15. return addNode(t.Next, v)
  16. }

依据工作原理,链表通常不含重复的项。此外,如果不是有序链表,新的节点通常会被添加在链表的尾部。

因此,addNode() 函数的功能就是向链表中添加新的节点。这个实现中使用 if 语句检查了三种不同的情况。第一种情况,检查要处理的链表是否为空。第二种情况,检查将要插入的值是否已经存在。第三种情况,检查是否已经到达了链表的末端,这时,使用 t.Next = &Node{v, nil} 将含有给定值的新节点加入链表的末端。如果所有的情况都不满足,则使用 return addNode(t.Next, v) 对链表中下一个节点调用 addNode(),重复上面的过程。

linkedList.go 程序的第三个代码片段包含了 traverse() 函数的实现:

  1. func traverse(t *Node) {
  2. if t == nil {
  3. fmt.Println("-> Empty list!")
  4. return
  5. }
  6. for t != nil {
  7. fmt.Printf("%d -> ", t.Value)
  8. t = t.Next
  9. }
  10. fmt.Println()
  11. }

linkedList.go 的第四部分如下:

  1. func lookupNode(t *Node, v int) bool {
  2. if root == nil {
  3. t = &Node{v, nil}
  4. root = t
  5. return false
  6. }
  7. if v == t.Value {
  8. return true
  9. }
  10. if t.Next == nil {
  11. return false
  12. }
  13. return lookupNode(t.Next, v)
  14. }
  15. func size(t *Node) int {
  16. if t == nil {
  17. fmt.Println("-> Empty list!")
  18. return 0
  19. }
  20. i := 0
  21. for t != nil {
  22. i++
  23. t = t.Next
  24. }
  25. return i
  26. }

这一部分包含了两个非常方便的函数——lookupNode()size() 的实现。前一个函数检查链表中是否存在给定的元素,后一个函数返回链表的大小,也就是链表中节点的数量。

lookupNode() 函数实现背后的逻辑很容易理解:依次访问单向链表中所有的元素来查找你想要的值。如果你从头到尾都没找到想要的值,那就说明链表中没有这个值。

linkedList.go 的最后一部分包含 main() 函数的实现:

  1. func main() {
  2. fmt.Println(root)
  3. root = nil
  4. traverse(root)
  5. addNode(root, 1)
  6. addNode(root, -1)
  7. traverse(root)
  8. addNode(root, 10)
  9. addNode(root, 5)
  10. addNode(root, 45)
  11. addNode(root, 5)
  12. addNode(root, 5)
  13. traverse(root)
  14. addNode(root, 100)
  15. traverse(root)
  16. if lookupNode(root, 100) {
  17. fmt.Println("Node exists!")
  18. } else {
  19. fmt.Println("Node does not exist!")
  20. }
  21. if lookupNode(root, -100) {
  22. fmt.Println("Node exists!")
  23. } else {
  24. fmt.Println("Node does not exist!")
  25. }
  26. }

执行 linkedList.go 将生成如下的输出:

  1. $ go run linkedList.go
  2. &{0 <nil>}
  3. -> Empty list!
  4. 1 -> -1 ->
  5. Node already exists: 5
  6. Node already exists: 5
  7. 1 -> -1 -> 10 -> 5 -> 45 ->
  8. 1 -> -1 -> 10 -> 5 -> 45 -> 100 ->
  9. Node exists!
  10. Node does not exist!