手擼golang 基本數據結構與算法 棧

手擼golang 基本數據結構與算法 棧

緣起

最近閱讀<<個人第一本算法書>>(【日】石田保輝;宮崎修一)
本系列筆記擬採用golang練習之golang

棧(也叫堆棧)也是一種數據呈線性排列的數據結構,
不過在這種結構中,
咱們只能訪問最新添加的數據。

棧就像是一摞書,
拿到新書時咱們會把它放在書堆的最上面,
取書時也只能從最上面的新書開始取。

像棧這種最後添加的數據最早被取出,
即「後進先出」的結構,
咱們稱爲Last In First Out,簡稱LIFO。

摘自 <<個人第一本算法書>>(【日】石田保輝;宮崎修一)

目標

  • 以數組爲基礎實現一個LIFO棧
  • 能夠指定數組的初始容量大小
  • 當元素數量超過容量時, 自動以2倍率速度擴容
  • 提供免拷貝的迭代器, 以遍歷堆棧, 並能檢測迭代版本錯誤(Concurrent Modification Error)

設計

  • IStack: 堆棧的接口
  • IStackIterator: 堆棧迭代器的接口
  • tArrayStack: 基於自擴容數組的堆棧, 實現IStack接口
  • tStackIterator: 免拷貝的堆棧迭代器, 實現IStackIterator接口

單元測試

stack_test.go算法

package data_structure

import (
    st "learning/gooop/data_structure/stack"
    "testing"
)

func Test_Stack(t *testing.T) {
    fnAssertTrue := func(b bool, msg string) {
        if !b {
            panic(msg)
        }
    }

    stack := st.NewArrayStack(2)
    state := stack.String()
    t.Log(state)
    fnAssertTrue(state == "c=2,t=-1,v=0,items:", "state error")

    stack.Push(0)
    state = stack.String()
    t.Log(state)
    fnAssertTrue(state == "c=2,t=0,v=1,items:0", "state error")

    stack.Push(1)
    state = stack.String()
    t.Log(state)
    fnAssertTrue(state == "c=2,t=1,v=2,items:0,1", "state error")

    stack.Push(2)
    state = stack.String()
    t.Log(state)
    fnAssertTrue(state == "c=4,t=2,v=3,items:0,1,2", "state error")

    e,v := stack.Peek()
    fnAssertTrue(e == nil, "expecting e == nil")
    fnAssertTrue(v == 2, "expecting value 2")

    e,v = stack.Pop()
    state = stack.String()
    t.Log(state)
    fnAssertTrue(e == nil, "expecting e == nil")
    fnAssertTrue(v == 2, "expecting value 2")
    fnAssertTrue(state == "c=4,t=1,v=4,items:0,1", "state error")

    e,v = stack.Pop()
    state = stack.String()
    t.Log(state)
    fnAssertTrue(e == nil, "expecting e == nil")
    fnAssertTrue(v == 1, "expecting value 1")
    fnAssertTrue(state == "c=4,t=0,v=5,items:0", "state error")

    e,v = stack.Pop()
    state = stack.String()
    t.Log(state)
    fnAssertTrue(e == nil, "expecting e == nil")
    fnAssertTrue(v == 0, "expecting value 0")
    fnAssertTrue(state == "c=4,t=-1,v=6,items:", "state error")

    e,v = stack.Pop()
    fnAssertTrue(e != nil, "expecting e != nil")

    iter := stack.Iterator()
    fnAssertTrue(iter.More() == false, "expecting More() == false")
    e,v = iter.Next()
    fnAssertTrue(e != nil, "expecting e != nil")

    stack.Push(0)
    state = stack.String()
    t.Log(state)
    fnAssertTrue(state == "c=4,t=0,v=7,items:0", "state error")
    fnAssertTrue(iter.More() == false, "expecting More() == false")
    e,v = iter.Next()
    fnAssertTrue(e != nil, "expecting e != nil")

    stack.Push(1)
    state = stack.String()
    t.Log(state)
    fnAssertTrue(state == "c=4,t=1,v=8,items:0,1", "state error")
    iter = stack.Iterator()
    fnAssertTrue(iter.More() == true, "expecting More() == true")
    e,v = iter.Next()
    fnAssertTrue(e == nil && v  == 0, "expecting v == 0")
    e,v = iter.Next()
    fnAssertTrue(e == nil && v  == 1, "expecting v == 1")
}

測試輸出

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

IStack.go

堆棧的接口數組

package stack

type IStack interface {
    Size() int
    IsEmpty() bool
    IsNotEmpty() bool

    Push(value interface{})
    Pop() (error, interface{})
    Peek() (error, interface{})

    Iterator() IStackIterator
    String() string
}

IStackIterator.go

堆棧迭代器的接口數據結構

package stack

type IStackIterator interface {
    More() bool
    Next() (error,interface{})
}

tArrayStack.go

基於自擴容數組的堆棧, 實現IStack接口oop

package stack

import (
    "errors"
    "fmt"
    "strings"
)

type tArrayStack struct {
    items []interface{}
    capacity int
    top int
    version int64
}

var gEmptyStackError = errors.New("empty stack")

func NewArrayStack(capacity int) IStack {
    if capacity < 0 {
        capacity = 0
    }

    return &tArrayStack{
        items: make([]interface{}, capacity),
        capacity: capacity,
        top: -1,
    }
}

func (me *tArrayStack) Size() int {
    return me.top + 1
}

func (me *tArrayStack) IsEmpty() bool {
    return me.Size() <= 0
}

func (me *tArrayStack) IsNotEmpty() bool {
    return !me.IsEmpty()
}

func (me *tArrayStack) Push(value interface{}) {
    me.ensureCapacity(me.Size() + 1)
    me.top++
    me.items[me.top] = value
    me.version++
}

func (me *tArrayStack) ensureCapacity(size int) {
    if me.capacity >= size {
        return
    }

    for ;me.capacity<size; {
        me.capacity = maxInt(me.capacity*2, me.capacity+1)
    }

    newItems := make([]interface{}, me.capacity)
    copy(newItems, me.items)
    me.items = newItems
}

func maxInt(x, y int) int {
    if x >= y {
        return x
    }
    return y
}

func (me *tArrayStack) Pop() (error, interface{}) {
    if me.IsEmpty() {
        return gEmptyStackError, nil
    }

    i := me.top
    me.top--
    me.version++
    return nil, me.items[i]
}

func (me *tArrayStack) Peek() (error, interface{}) {
    if me.IsEmpty() {
        return gEmptyStackError, nil
    }

    return nil, me.items[me.top]
}

func (me *tArrayStack) Iterator() IStackIterator {
    return newStackIterator(me)
}

func (me *tArrayStack) String() string {
    itemStrings := make([]string, me.Size())
    for i:=0;i<me.Size();i++ {
        itemStrings[i] = fmt.Sprintf("%v", me.items[i])
    }

    return fmt.Sprintf("c=%v,t=%v,v=%v,items:%s", me.capacity, me.top, me.version, strings.Join(itemStrings, ","))
}

tStackIterator.go

免拷貝的堆棧迭代器, 實現IStackIterator接口單元測試

package stack

import "errors"

type tStackIterator struct {
    stack *tArrayStack
    pos int
    version int64
}

var gNullStackError = errors.New("stack is null")
var gNoMoreElementError = errors.New("no more element")
var gConcurrentModificationError = errors.New("concurrent modification error")

func newStackIterator(stack *tArrayStack) IStackIterator {
    return &tStackIterator{
        stack: stack,
        pos: -1,
        version: stack.version,
    }
}

func (me *tStackIterator) More() bool {
    if me.stack == nil {
        return false
    }
    if me.version != me.stack.version {
        return false
    }
    return me.pos < me.stack.top
}

func (me *tStackIterator) Next() (error, interface{}) {
    if me.stack == nil {
        return gNullStackError, nil
    }
    if me.version != me.stack.version {
        return gConcurrentModificationError, nil
    }
    if me.pos >= me.stack.top {
        return gNoMoreElementError, nil
    }

    me.pos++
    return nil, me.stack.items[me.pos]
}

(end)測試

相關文章
相關標籤/搜索