diff --git a/arraystack/arraystack.go b/arraystack/arraystack.go deleted file mode 100644 index 43286e0..0000000 --- a/arraystack/arraystack.go +++ /dev/null @@ -1 +0,0 @@ -package astack diff --git a/arraystack/arraystack_test.go b/arraystack/arraystack_test.go deleted file mode 100644 index 43286e0..0000000 --- a/arraystack/arraystack_test.go +++ /dev/null @@ -1 +0,0 @@ -package astack diff --git a/lastack/lastack.go b/lastack/lastack.go new file mode 100644 index 0000000..65c2b2c --- /dev/null +++ b/lastack/lastack.go @@ -0,0 +1,159 @@ +package lastack + +import ( + "github.com/davecgh/go-spew/spew" +) + +type Node struct { + elements []interface{} + cur int + down *Node +} + +type Stack struct { + top *Node + cache *Node + size int +} + +func (as *Stack) grow() bool { + if as.top.cur+1 == cap(as.top.elements) { + + var grownode *Node + if as.cache != nil { + grownode = as.cache + grownode.cur = -1 + as.cache = nil + } else { + var growsize int + if as.size <= 200 { + growsize = as.size * 2 + } else { + growsize = 200 + as.size/4 + } + grownode = &Node{elements: make([]interface{}, growsize, growsize), cur: -1} + } + + grownode.down = as.top + as.top = grownode + return true + } + + return false +} + +func (as *Stack) cacheRemove() bool { + if as.top.cur == 0 && as.top.down != nil { + as.cache = as.top + as.top = as.top.down + as.cache.down = nil + return true + } + + return false +} + +func New() *Stack { + s := &Stack{} + s.size = 0 + s.top = &Node{elements: make([]interface{}, 8, 8), cur: -1} + return s +} + +func (as *Stack) Clear() { + as.size = 0 + as.top = nil + as.cache = nil +} + +func (as *Stack) Empty() bool { + return as.size == 0 +} + +func (as *Stack) Size() int { + return as.size +} + +func (as *Stack) String() string { + content := "" + cur := as.top + for ; cur != nil; cur = cur.down { + for i, _ := range cur.elements { + if cur.cur >= i { + content += spew.Sprint(cur.elements[cur.cur-i]) + " " + } + } + } + + if len(content) > 0 { + content = content[0 : len(content)-1] + } else { + content = "" + } + + return content +} + +func (as *Stack) Values() []interface{} { + result := make([]interface{}, as.size, as.size) + + cur := as.top + n := 0 + for ; cur != nil; cur = cur.down { + for i, _ := range cur.elements { + if cur.cur >= i { + result[n] = cur.elements[cur.cur-i] + n++ + } + } + } + + return result +} + +func (as *Stack) Get(idx int) (interface{}, bool) { + if idx < 0 { + return nil, false + } + + cur := as.top + for cur != nil && idx-cur.cur > 0 { + idx = idx - cur.cur - 1 + cur = cur.down + } + + if cur == nil { + return nil, false + } + + return cur.elements[cur.cur-idx], true +} + +func (as *Stack) Push(v interface{}) { + as.grow() + as.top.cur++ + as.top.elements[as.top.cur] = v + as.size++ +} + +func (as *Stack) Pop() (interface{}, bool) { + if as.size <= 0 { + return nil, false + } + + as.size-- + if as.cacheRemove() { + return as.cache.elements[as.cache.cur], true + } + + epop := as.top.elements[as.top.cur] + as.top.cur-- + return epop, true +} + +func (as *Stack) Peek() (interface{}, bool) { + if as.size <= 0 { + return nil, false + } + return as.top.elements[as.top.cur], true +} diff --git a/lastack/lastack_test.go b/lastack/lastack_test.go new file mode 100644 index 0000000..f412438 --- /dev/null +++ b/lastack/lastack_test.go @@ -0,0 +1,135 @@ +package lastack + +import ( + "testing" + + "github.com/emirpasic/gods/stacks/arraystack" + + "github.com/Pallinder/go-randomdata" +) + +func TestPush(t *testing.T) { + s := New() + for i := 0; i < 10; i++ { + v := randomdata.Number(0, 10) + s.Push(v) + t.Error(v) + t.Error(s.String(), " size ", s.size) + } + + t.Error(s.Values()) + + for i := 0; i < 10; i++ { + v, ok := s.Pop() + t.Error(v, ok) + t.Error(s.String(), " size ", s.size) + } + + for i := 0; i < 10; i++ { + v := randomdata.Number(0, 10) + s.Push(v) + } + + for i := -1; i < 11; i++ { + v, ok := s.Get(i) + t.Error(v, ok) + } + +} + +func BenchmarkGet(b *testing.B) { + s := New() + b.N = 20000000 + + for i := 0; i < b.N; i++ { + v := randomdata.Number(0, 65535) + s.Push(v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + s.Get(i) + } +} + +func BenchmarkPush(b *testing.B) { + s := New() + for i := 0; i < b.N; i++ { + v := randomdata.Number(0, 65535) + s.Push(v) + } +} + +func BenchmarkGodsPush(b *testing.B) { + s := arraystack.New() + for i := 0; i < b.N; i++ { + v := randomdata.Number(0, 65535) + s.Push(v) + } +} + +func BenchmarkPop(b *testing.B) { + s := New() + b.N = 20000000 + + for i := 0; i < b.N; i++ { + v := randomdata.Number(0, 65535) + s.Push(v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + s.Pop() + } +} + +func BenchmarkGodsPop(b *testing.B) { + s := arraystack.New() + b.N = 20000000 + + for i := 0; i < b.N; i++ { + v := randomdata.Number(0, 65535) + s.Push(v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + s.Pop() + } +} + +func BenchmarkValues(b *testing.B) { + s := New() + for i := 0; i < b.N; i++ { + v := randomdata.Number(0, 65535) + s.Push(v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + s.Values() + } +} + +func BenchmarkGodsValues(b *testing.B) { + s := arraystack.New() + for i := 0; i < b.N; i++ { + v := randomdata.Number(0, 65535) + s.Push(v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + s.Values() + } +}