From 09f75253fec0de23cf8f5b556ea5296533e3fde7 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Thu, 5 Mar 2015 21:10:37 +0100 Subject: [PATCH] optimizing the array stack to shrink array by factor of 1.5, now array stack is faster than linked list stack --- README.md | 2 +- stacks/arraystack/arraystack.go | 35 ++++++++++++------- stacks/arraystack/arraystack_test.go | 4 +-- .../linkedliststack/linkedliststack_test.go | 4 +-- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index ab90ffa..d3803f7 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Collections and data structures found in other languages: Java Collections, C++ **Memory efficient algorithms**: - - Avoiding to keep consume memory by using optimal algorithms and data structures for the given set of problems. + - Avoiding to consume memory by using optimal algorithms and data structures for the given set of problems, e.g. red-black tree in case of TreeMap to avoid keeping redundant sorted array of keys in memory. **Easy to use library**: diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 8dc2b4e..8034731 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -17,7 +17,6 @@ with this distribution for more information. */ // Implementation of stack using a slice. -// Use LinkedListStack rather than this Arraystack, because LinkedListStack is a lot faster more memory efficient. // Structure is not thread safe. // References: http://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29 @@ -35,26 +34,37 @@ func assertInterfaceImplementation() { type Stack struct { items []interface{} + top int } // Instantiates a new empty stack func New() *Stack { - return &Stack{} + return &Stack{top: -1} } // Pushes a value onto the top of the stack func (stack *Stack) Push(value interface{}) { - stack.items = append(stack.items, value) + // Increase when capacity is reached by a factor of 1.5 and add one so it grows when size is zero + if stack.top+1 >= cap(stack.items) { + currentSize := len(stack.items) + sizeIncrease := int(1.5*float32(currentSize) + 1.0) + newSize := currentSize + sizeIncrease + newItems := make([]interface{}, newSize, newSize) + copy(newItems, stack.items) + stack.items = newItems + } + stack.top += 1 + stack.items[stack.top] = value } // Pops (removes) top element on stack and returns it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to pop. func (stack *Stack) Pop() (value interface{}, ok bool) { - size := len(stack.items) - if size > 0 { - value = stack.items[size-1] - stack.items = append([]interface{}(nil), stack.items[:size-1]...) - return value, true + if stack.top >= 0 { + value, ok = stack.items[stack.top], true + // TODO shrink slice at some point + stack.top -= 1 + return } return nil, false } @@ -62,21 +72,20 @@ func (stack *Stack) Pop() (value interface{}, ok bool) { // Returns top element on the stack without removing it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to peek. func (stack *Stack) Peek() (value interface{}, ok bool) { - size := len(stack.items) - if size > 0 { - return stack.items[size-1], true + if stack.top >= 0 { + return stack.items[stack.top], true } return nil, false } // Returns true if stack does not contain any elements. func (stack *Stack) Empty() bool { - return len(stack.items) == 0 + return stack.Size() == 0 } // Returns number of elements within the stack. func (stack *Stack) Size() int { - return len(stack.items) + return stack.top + 1 } func (stack *Stack) String() string { diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 2afc14c..ff46eed 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -72,8 +72,8 @@ func TestArrayStack(t *testing.T) { } func BenchmarkArrayStack(b *testing.B) { - // Slow in comparison to the LinkedListStack - // BenchmarkArrayStack 50 31760994 ns/op 8540863 B/op 2010 allocs/op + // Faster in comparison to the LinkedListStack + // BenchmarkArrayStack 5000 325010 ns/op 71648 B/op 1009 allocs/op // BenchmarkLinkedListStack 5000 390812 ns/op 40016 B/op 2001 allocs/op for i := 0; i < b.N; i++ { stack := New() diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index c3ed37a..b11f7d2 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -72,8 +72,8 @@ func TestLinkedListStack(t *testing.T) { } func BenchmarkLinkedListStack(b *testing.B) { - // Faster in comparison to the ArrayStack - // BenchmarkArrayStack 50 31760994 ns/op 8540863 B/op 2010 allocs/op + // Slower in comparison to the ArrayStack + // BenchmarkArrayStack 5000 325010 ns/op 71648 B/op 1009 allocs/op // BenchmarkLinkedListStack 5000 390812 ns/op 40016 B/op 2001 allocs/op for i := 0; i < b.N; i++ { stack := New()