栈的特性

栈是一种FILO类型的数据结构,FILO 即 Fisrt In Last Out,也就是先进后出,也可以说是后进先出。

栈实现的三种方式

  1. 利用Golang的slice


  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. // Item the type of the stack
  7. type Item interface{}
  8. // ItemStack the stack of Items
  9. type ItemStack struct {
  10. items []Item
  11. lock sync.RWMutex
  12. }
  13. // New creates a new ItemStack
  14. func NewStack() *ItemStack {
  15. s := &ItemStack{}
  16. s.items = []Item{}
  17. return s
  18. }
  19. // Pirnt prints all the elements
  20. func (s *ItemStack) Print() {
  21. fmt.Println(s.items)
  22. }
  23. // Push adds an Item to the top of the stack
  24. func (s *ItemStack) Push(t Item) {
  25. s.lock.Lock()
  26. s.lock.Unlock()
  27. s.items = append(s.items, t)
  28. }
  29. // Pop removes an Item from the top of the stack
  30. func (s *ItemStack) Pop() Item {
  31. s.lock.Lock()
  32. defer s.lock.Unlock()
  33. if len(s.items) == 0 {
  34. return nil
  35. }
  36. item := s.items[len(s.items)-1]
  37. s.items = s.items[0 : len(s.items)-1]
  38. return item
  39. }

此方式特点:

  1. 利用Golang的Slice,足够简单。
  2. 允许添加任意类型的元素。
  3. Push和Pop有加锁处理,线程安全。
  4. 在一些文章里(Reddit)提到,使用slice作为Stack的底层支持,速度更快。但是,slice最大的问题其实是存在一个共用底层数组的的问题,哪怕你不断的Pop,但可能对于Golang来说,其占用的内存,并不一定减少。

性能测试

  1. package main
  2. import (
  3. "testing"
  4. )
  5. var stack *ItemStack
  6. func init() {
  7. stack = NewStack()
  8. }
  9. func Benchmark_Push(b *testing.B) {
  10. for i := 0; i < b.N; i++ { //use b.N for looping
  11. stack.Push("test")
  12. }
  13. }
  14. func Benchmark_Pop(b *testing.B) {
  15. b.StopTimer()
  16. for i := 0; i < b.N; i++ { //use b.N for looping
  17. stack.Push("test")
  18. }
  19. b.StartTimer()
  20. for i := 0; i < b.N; i++ { //use b.N for looping
  21. stack.Pop()
  22. }
  23. }
  1. 利用Golang的container/list内置包 ```go package main

import ( “container/list” “sync” )

type Stack struct { list list.List lock sync.RWMutex }

func NewStack() *Stack { list := list.New() l := &sync.RWMutex{} return &Stack{list, l} }

func (stack *Stack) Push(value interface{}) { stack.lock.Lock() defer stack.lock.Unlock() stack.list.PushBack(value) }

func (stack *Stack) Pop() interface{} { stack.lock.Lock() defer stack.lock.Unlock() e := stack.list.Back() if e != nil { stack.list.Remove(e) return e.Value } return nil }

func (stack *Stack) Peak() interface{} { e := stack.list.Back() if e != nil { return e.Value }

  1. return nil

}

func (stack *Stack) Len() int { return stack.list.Len() }

func (stack *Stack) Empty() bool { return stack.list.Len() == 0 }

  1. container/list 是一个链表。用链表模拟栈,要么都向链表的最后做pushpop,要么都向链表的起点做pushpop
  2. 3. godoc的实现参考(自定义数据结构实现)
  3. <br />
  4. ```go
  5. package main
  6. import (
  7. "sync"
  8. )
  9. type (
  10. Stack struct {
  11. top *node
  12. length int
  13. lock *sync.RWMutex
  14. }
  15. node struct {
  16. value interface{}
  17. prev *node
  18. }
  19. )
  20. // Create a new stack
  21. func NewStack() *Stack {
  22. return &Stack{nil, 0, &sync.RWMutex{}}
  23. }
  24. // Return the number of items in the stack
  25. func (this *Stack) Len() int {
  26. return this.length
  27. }
  28. // View the top item on the stack
  29. func (this *Stack) Peek() interface{} {
  30. if this.length == 0 {
  31. return nil
  32. }
  33. return this.top.value
  34. }
  35. // Pop the top item of the stack and return it
  36. func (this *Stack) Pop() interface{} {
  37. this.lock.Lock()
  38. defer this.lock.Unlock()
  39. if this.length == 0 {
  40. return nil
  41. }
  42. n := this.top
  43. this.top = n.prev
  44. this.length--
  45. return n.value
  46. }
  47. // Push a value onto the top of the stack
  48. func (this *Stack) Push(value interface{}) {
  49. this.lock.Lock()
  50. defer this.lock.Unlock()
  51. n := &node{value, this.top}
  52. this.top = n
  53. this.length++
  54. }

此方式特点:

  1. 实现比较精巧,唯一需要理解的地方就是 node 结构体中,prev 的部分,它指向的是前一个node成员。
  2. 允许添加任意类型的元素。
  3. Push和Pop是线程安全的。
特性对比 push速度 pop速度 push内存分配 pop内存分配
基于slice 222ns/op 65ns/op 94B/op 0B/op
container/list链表 222ns/op 73.5ns/op 48B/op 0B/op
自定义数据结构 178ns/op 75ns/op 32B/op 0B/op