Go 语言实现栈

现在是时候看看如何使用 Go 语言实现栈了。相关的细节在 stack.go 源文件中。同样,栈的实现也会用到链表。如你所知,你需要两个函数:一个 Push() 函数将元素放入栈中,一个 Pop() 函数从栈中删除元素。单独使用一个变量保存栈中元素的数量是个很实用的方法,这样即使不访问链表也能判断栈是否为空,不过这不是必须的。

stack.go 中的源代码将分四个部分介绍。第一部分如下:

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

stack.go 的第二部分包含了 Push() 函数的实现:

  1. func Push(v int) bool {
  2. if stack == nil {
  3. stack = &Node{v, nil}
  4. size = 1
  5. return true
  6. }
  7. temp := &Node{v, nil}
  8. temp.Next = stack
  9. stack = temp
  10. size++
  11. return true
  12. }

如果栈为空就创建一个新节点(temp)并将它放在当前栈的最前面,然后新节点会成为栈的头节点。这个版本的 Push() 函数永远返回 true。对于存储空间有限的栈,你可以修改一下,在栈将要溢出时返回 false

第三部分包含 Pop() 函数的实现:

  1. func Pop(t *Node) (int, bool) {
  2. if size == 0 {
  3. return 0, false
  4. }
  5. if size == 1 {
  6. size = 0
  7. stack = nil
  8. return t.Value, true
  9. }
  10. stack = stack.Next
  11. size--
  12. return t.Value, true
  13. }

stack.go 的第四个代码段如下:

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

由于这里的栈是使用链表实现的,所以也用链表的方式进行遍历。

stack.go 的最后一部分如下:

  1. func main() {
  2. stack = nil
  3. v, b := Pop(stack)
  4. if b {
  5. fmt.Print(v, " ")
  6. } else {
  7. fmt.Println("Pop() failed!")
  8. }
  9. Push(100)
  10. traverse(stack)
  11. Push(200)
  12. traverse(stack)
  13. for i := 0; i < 10; i++ {
  14. Push(i)
  15. }
  16. for i := 0; i < 15; i++ {
  17. v, b := Pop(stack)
  18. if b {
  19. fmt.Print(v, " ")
  20. } else {
  21. break
  22. }
  23. }
  24. fmt.Println()
  25. traverse(stack)
  26. }

如你所见,stack.go 的源代码比 queue.go 的稍微短一点,这主要是因为栈背后的思想比队列更简单。

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

  1. Pop() failed!
  2. 100 ->
  3. 200 -> 100 ->
  4. 9 8 7 6 5 4 3 2 1 0 200 100
  5. Empty Stack!

现在为止,你已经知道了如何使用链表实现哈希表、队列和栈。这些例子会让你意识到,在一般情况下链表对于编程和计算机科学来说是多么的有效和重要!