Go 语言实现双向链表

实现了双向链表的 Go 程序是 doublyLList.go,我们将分为五个部分来介绍。双向链表背后的基本思想和单向链表相同。不过由于双向链表中每个节点都有两个指针,所以操作更冗杂。

doublyLList.go 的第一部分如下:

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

这部分中使用 Go 的结构体定义了双向链表的节点。不过这次的 struct 中有两个指针字段,原因就不必多说了。

doublyLList.go 的第二部分包含如下的 Go 代码:

  1. func addNode(t *Node, v int) int {
  2. if root == nil {
  3. t = &Node{v, nil, 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. temp := t
  13. t.Next = &Node{v, temp, nil}
  14. return -2
  15. }
  16. return addNode(t.Next, v)
  17. }

就像单向链表中一样,新的节点都被添加在当前双向链表的末端。这并不是强制性的,你也可以选择对这个双向链表进行排序。

doublyLList.go 的第三部分如下:

  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. }
  12. func reverse(t *Node) {
  13. if t == nil {
  14. fmt.Println("-> Empty list!")
  15. return
  16. }
  17. temp := t
  18. for t != nil {
  19. temp = t
  20. t = t.Next
  21. }
  22. for temp.Previous != nil {
  23. fmt.Printf("%d -> ", temp.Value)
  24. temp = temp.Previous
  25. }
  26. fmt.Printf("%d -> ", temp.Value)
  27. fmt.Println()
  28. }

这是 traverse()reverse() 函数的 Go 代码。traverse() 的实现和 linkedList.go 中的一样。但是 reverse() 背后的逻辑很有趣。因为没有指向双向链表尾节点的指针,所以我们必须先从头向后访问,直到找到尾节点,之后才能反向遍历所有的节点。

doublyLList.go 的第四部分包含如下的 Go 代码:

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

doublyLList.go 的最后一个代码段包含如下的 Go 代码:

  1. var root = new(Node)
  2. func main() {
  3. fmt.Println(root)
  4. root = nil
  5. traverse(root)
  6. addNode(root, 1)
  7. addNode(root, 1)
  8. traverse(root)
  9. addNode(root, 10)
  10. addNode(root, 5)
  11. addNode(root, 0)
  12. addNode(root, 0)
  13. traverse(root)
  14. addNode(root, 100)
  15. fmt.Println("Size:", size(root))
  16. traverse(root)
  17. reverse(root)
  18. }

执行 doublyLList.go,你将得到如下输出:

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

如你所见,reverse() 函数效果很好!