1. 程式人生 > >golang實現簡單的棧

golang實現簡單的棧

棧的ADT


資料

棧的資料物件集合為{a1,a2,a3...an},具有相同資料型別,有唯一前驅後續


操作

  • InitStack() *Stack //初始化操作,建立一個空棧
  • Clear() //清空棧
  • IsEmpty() bool //棧是否為空,若棧為空,返回 true,否則 返回 false。
  • Peek() interface{} //若棧存在且非空,返回棧頂元素。
  • Push(data interface{}) //將資料data壓入棧
  • Pop() //若棧不為空,出棧
  • Length() int //返回棧中元素個數

程式碼實現

stack.go

package stack

import (
    "sync"
)

type Stack struct {
    data     []interface{}
    length   int
    capacity int
    sync.Mutex
}

// 構建一個空棧
func InitStack() *Stack {
    return &Stack{data: make([]interface{}, 8), length: 0, capacity: 8}
}

// 壓棧操作
func (s *Stack) Push(data interface{}) {
    s.Lock()
    defer s.Unlock()

    if s.length+1 >= s.capacity {
        s.capacity <<= 1
        t := s.data
        s.data = make([]interface{}, s.capacity)
        copy(s.data, t)
    }

    s.data[s.length] = data
    s.length++
}

// 出棧操作
func (s *Stack) Pop() interface{} {
    s.Lock()
    defer s.Unlock()

    if s.length <= 0 {
        panic("int stack pop: index out of range")
    }

    t := s.data[s.length-1]
    s.data = s.data[:s.length-1]
    s.length--

    return t
}

// 返回棧頂元素
func (s *Stack) Peek() interface{} {
    s.Lock()
    defer s.Unlock()

    if s.length <= 0 {
        panic("empty stack")
    }

    return s.data[s.length-1]
}

// 返回當前棧元素個數
func (s *Stack) Count() int {
    s.Lock()
    defer s.Unlock()

    t := s.length

    return t
}

// 清空棧
func (s *Stack) Clear() {
    s.Lock()
    defer s.Unlock()

    s.data = make([]interface{}, 8)
    s.length = 0
    s.capacity = 8
}

// 棧是否為空
func (s *Stack) IsEmpty() bool {
    s.Lock()
    defer s.Unlock()
    b := s.length == 0
    return b
}

stack_test.go

package stack

import (
    "testing"

    gcv "github.com/smartystreets/goconvey/convey"
)

func TestInitStack(t *testing.T) {
    s := InitStack()
    gcv.Convey("棧不應該為空", t, func() {
        gcv.So(s, gcv.ShouldNotBeNil)
    })
}

func TestPush(t *testing.T) {
    s := InitStack()
    for i := 0; i < 100; i++ {
        s.Push(i)
    }
    gcv.Convey("入棧測試", t, func() {
        gcv.Convey("棧大小應該為100", func() {
            gcv.So(s.length, gcv.ShouldEqual, 100)
        })
        gcv.Convey("棧中元素應該為0-99", func() {
            gcv.So(func() bool {
                for i := 0; i < 100; i++ {
                    if s.data[i] != i {
                        return false
                    }
                }
                return true
            }(), gcv.ShouldEqual, true)
        })
    })
}

func TestPop(t *testing.T) {
    gcv.Convey("出棧測試", t, func() {
        gcv.Convey("棧中元素應該為99-0", func() {
            gcv.So(func() bool {
                s := InitStack()
                for i := 0; i < 100; i++ {
                    s.Push(i)
                }
                for i := 99; i > -1; i-- {
                    t := s.Pop().(int)
                    if t != i {
                        return false
                    }
                }
                return true
            }(), gcv.ShouldEqual, true)
        })
    })
}

func TestPeek(t *testing.T) {
    gcv.Convey("棧頂操作", t, func() {
        s := InitStack()
        s.Push(1)
        s.Push(2)
        tmp := s.Peek().(int)
        gcv.So(tmp, gcv.ShouldEqual, 2)
    })
}