缘起

最近阅读<<我的第一本算法书>>(【日】石田保辉;宫崎修一)
本系列笔记拟采用golang练习之

  1. 栈(也叫堆栈)也是一种数据呈线性排列的数据结构,
  2. 不过在这种结构中,
  3. 我们只能访问最新添加的数据。
  4. 栈就像是一摞书,
  5. 拿到新书时我们会把它放在书堆的最上面,
  6. 取书时也只能从最上面的新书开始取。
  7. 像栈这种最后添加的数据最先被取出,
  8. 即“后进先出”的结构,
  9. 我们称为Last In First Out,简称LIFO
  10. 摘自 <<我的第一本算法书>>(【日】石田保辉;宫崎修一)

目标

  • 以数组为基础实现一个LIFO栈
  • 可以指定数组的初始容量大小
  • 当元素数量超过容量时, 自动以2倍率速度扩容
  • 提供免拷贝的迭代器, 以遍历堆栈, 并能检测迭代版本错误(Concurrent Modification Error)

设计

  • IStack: 堆栈的接口
  • IStackIterator: 堆栈迭代器的接口
  • tArrayStack: 基于自扩容数组的堆栈, 实现IStack接口
  • tStackIterator: 免拷贝的堆栈迭代器, 实现IStackIterator接口

单元测试

stack_test.go

  1. package data_structure
  2. import (
  3. st "learning/gooop/data_structure/stack"
  4. "testing"
  5. )
  6. func Test_Stack(t *testing.T) {
  7. fnAssertTrue := func(b bool, msg string) {
  8. if !b {
  9. panic(msg)
  10. }
  11. }
  12. stack := st.NewArrayStack(2)
  13. state := stack.String()
  14. t.Log(state)
  15. fnAssertTrue(state == "c=2,t=-1,v=0,items:", "state error")
  16. stack.Push(0)
  17. state = stack.String()
  18. t.Log(state)
  19. fnAssertTrue(state == "c=2,t=0,v=1,items:0", "state error")
  20. stack.Push(1)
  21. state = stack.String()
  22. t.Log(state)
  23. fnAssertTrue(state == "c=2,t=1,v=2,items:0,1", "state error")
  24. stack.Push(2)
  25. state = stack.String()
  26. t.Log(state)
  27. fnAssertTrue(state == "c=4,t=2,v=3,items:0,1,2", "state error")
  28. e,v := stack.Peek()
  29. fnAssertTrue(e == nil, "expecting e == nil")
  30. fnAssertTrue(v == 2, "expecting value 2")
  31. e,v = stack.Pop()
  32. state = stack.String()
  33. t.Log(state)
  34. fnAssertTrue(e == nil, "expecting e == nil")
  35. fnAssertTrue(v == 2, "expecting value 2")
  36. fnAssertTrue(state == "c=4,t=1,v=4,items:0,1", "state error")
  37. e,v = stack.Pop()
  38. state = stack.String()
  39. t.Log(state)
  40. fnAssertTrue(e == nil, "expecting e == nil")
  41. fnAssertTrue(v == 1, "expecting value 1")
  42. fnAssertTrue(state == "c=4,t=0,v=5,items:0", "state error")
  43. e,v = stack.Pop()
  44. state = stack.String()
  45. t.Log(state)
  46. fnAssertTrue(e == nil, "expecting e == nil")
  47. fnAssertTrue(v == 0, "expecting value 0")
  48. fnAssertTrue(state == "c=4,t=-1,v=6,items:", "state error")
  49. e,v = stack.Pop()
  50. fnAssertTrue(e != nil, "expecting e != nil")
  51. iter := stack.Iterator()
  52. fnAssertTrue(iter.More() == false, "expecting More() == false")
  53. e,v = iter.Next()
  54. fnAssertTrue(e != nil, "expecting e != nil")
  55. stack.Push(0)
  56. state = stack.String()
  57. t.Log(state)
  58. fnAssertTrue(state == "c=4,t=0,v=7,items:0", "state error")
  59. fnAssertTrue(iter.More() == false, "expecting More() == false")
  60. e,v = iter.Next()
  61. fnAssertTrue(e != nil, "expecting e != nil")
  62. stack.Push(1)
  63. state = stack.String()
  64. t.Log(state)
  65. fnAssertTrue(state == "c=4,t=1,v=8,items:0,1", "state error")
  66. iter = stack.Iterator()
  67. fnAssertTrue(iter.More() == true, "expecting More() == true")
  68. e,v = iter.Next()
  69. fnAssertTrue(e == nil && v == 0, "expecting v == 0")
  70. e,v = iter.Next()
  71. fnAssertTrue(e == nil && v == 1, "expecting v == 1")
  72. }

测试输出

  1. $ go test -v stack_test.go
  2. === RUN Test_Stack
  3. stack_test.go:17: c=2,t=-1,v=0,items:
  4. stack_test.go:22: c=2,t=0,v=1,items:0
  5. stack_test.go:27: c=2,t=1,v=2,items:0,1
  6. stack_test.go:32: c=4,t=2,v=3,items:0,1,2
  7. stack_test.go:41: c=4,t=1,v=4,items:0,1
  8. stack_test.go:48: c=4,t=0,v=5,items:0
  9. stack_test.go:55: c=4,t=-1,v=6,items:
  10. stack_test.go:70: c=4,t=0,v=7,items:0
  11. stack_test.go:78: c=4,t=1,v=8,items:0,1
  12. --- PASS: Test_Stack (0.00s)
  13. PASS
  14. ok command-line-arguments 0.003s

IStack.go

堆栈的接口

  1. package stack
  2. type IStack interface {
  3. Size() int
  4. IsEmpty() bool
  5. IsNotEmpty() bool
  6. Push(value interface{})
  7. Pop() (error, interface{})
  8. Peek() (error, interface{})
  9. Iterator() IStackIterator
  10. String() string
  11. }

IStackIterator.go

堆栈迭代器的接口

  1. package stack
  2. type IStackIterator interface {
  3. More() bool
  4. Next() (error,interface{})
  5. }

tArrayStack.go

基于自扩容数组的堆栈, 实现IStack接口

  1. package stack
  2. import (
  3. "errors"
  4. "fmt"
  5. "strings"
  6. )
  7. type tArrayStack struct {
  8. items []interface{}
  9. capacity int
  10. top int
  11. version int64
  12. }
  13. var gEmptyStackError = errors.New("empty stack")
  14. func NewArrayStack(capacity int) IStack {
  15. if capacity < 0 {
  16. capacity = 0
  17. }
  18. return &tArrayStack{
  19. items: make([]interface{}, capacity),
  20. capacity: capacity,
  21. top: -1,
  22. }
  23. }
  24. func (me *tArrayStack) Size() int {
  25. return me.top + 1
  26. }
  27. func (me *tArrayStack) IsEmpty() bool {
  28. return me.Size() <= 0
  29. }
  30. func (me *tArrayStack) IsNotEmpty() bool {
  31. return !me.IsEmpty()
  32. }
  33. func (me *tArrayStack) Push(value interface{}) {
  34. me.ensureCapacity(me.Size() + 1)
  35. me.top++
  36. me.items[me.top] = value
  37. me.version++
  38. }
  39. func (me *tArrayStack) ensureCapacity(size int) {
  40. if me.capacity >= size {
  41. return
  42. }
  43. for ;me.capacity<size; {
  44. me.capacity = maxInt(me.capacity*2, me.capacity+1)
  45. }
  46. newItems := make([]interface{}, me.capacity)
  47. copy(newItems, me.items)
  48. me.items = newItems
  49. }
  50. func maxInt(x, y int) int {
  51. if x >= y {
  52. return x
  53. }
  54. return y
  55. }
  56. func (me *tArrayStack) Pop() (error, interface{}) {
  57. if me.IsEmpty() {
  58. return gEmptyStackError, nil
  59. }
  60. i := me.top
  61. me.top--
  62. me.version++
  63. return nil, me.items[i]
  64. }
  65. func (me *tArrayStack) Peek() (error, interface{}) {
  66. if me.IsEmpty() {
  67. return gEmptyStackError, nil
  68. }
  69. return nil, me.items[me.top]
  70. }
  71. func (me *tArrayStack) Iterator() IStackIterator {
  72. return newStackIterator(me)
  73. }
  74. func (me *tArrayStack) String() string {
  75. itemStrings := make([]string, me.Size())
  76. for i:=0;i<me.Size();i++ {
  77. itemStrings[i] = fmt.Sprintf("%v", me.items[i])
  78. }
  79. return fmt.Sprintf("c=%v,t=%v,v=%v,items:%s", me.capacity, me.top, me.version, strings.Join(itemStrings, ","))
  80. }

tStackIterator.go

免拷贝的堆栈迭代器, 实现IStackIterator接口

  1. package stack
  2. import "errors"
  3. type tStackIterator struct {
  4. stack *tArrayStack
  5. pos int
  6. version int64
  7. }
  8. var gNullStackError = errors.New("stack is null")
  9. var gNoMoreElementError = errors.New("no more element")
  10. var gConcurrentModificationError = errors.New("concurrent modification error")
  11. func newStackIterator(stack *tArrayStack) IStackIterator {
  12. return &tStackIterator{
  13. stack: stack,
  14. pos: -1,
  15. version: stack.version,
  16. }
  17. }
  18. func (me *tStackIterator) More() bool {
  19. if me.stack == nil {
  20. return false
  21. }
  22. if me.version != me.stack.version {
  23. return false
  24. }
  25. return me.pos < me.stack.top
  26. }
  27. func (me *tStackIterator) Next() (error, interface{}) {
  28. if me.stack == nil {
  29. return gNullStackError, nil
  30. }
  31. if me.version != me.stack.version {
  32. return gConcurrentModificationError, nil
  33. }
  34. if me.pos >= me.stack.top {
  35. return gNoMoreElementError, nil
  36. }
  37. me.pos++
  38. return nil, me.stack.items[me.pos]
  39. }

(end)