-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Expose an interface for the stack package
- Loading branch information
Showing
10 changed files
with
340 additions
and
280 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package stack | ||
|
||
import ( | ||
"container/list" | ||
) | ||
|
||
// doublyLinkedList is an implementation of stack.Interface using the doubly linked list provided by `container/list` as its underlying storage. | ||
type doublyLinkedList[T any] struct { | ||
stack *list.List | ||
} | ||
|
||
func NewDoublyLinkedList[T any]() Interface[T] { | ||
return &doublyLinkedList[T]{ | ||
stack: list.New(), | ||
} | ||
} | ||
|
||
// Push add a value into our stack | ||
func (dl *doublyLinkedList[T]) Push(val T) { | ||
dl.stack.PushFront(val) | ||
} | ||
|
||
// Peek return last inserted element(top of the stack) without removing it from the stack | ||
// If the stack is empty, ErrStackEmpty error is returned | ||
func (dl *doublyLinkedList[T]) Peek() (T, error) { | ||
var result T | ||
if dl.Empty() { | ||
return result, ErrStackEmpty | ||
} | ||
|
||
element := dl.stack.Front() | ||
if element == nil { | ||
return result, ErrStackEmpty | ||
} | ||
|
||
result = element.Value.(T) | ||
return result, nil | ||
} | ||
|
||
// Pop is return last value that insert into our stack | ||
// also it will remove it in our stack | ||
func (dl *doublyLinkedList[T]) Pop() (T, error) { | ||
var result T | ||
if dl.Empty() { | ||
return result, ErrStackEmpty | ||
} | ||
|
||
element := dl.stack.Front() | ||
if element == nil { | ||
return result, ErrStackEmpty | ||
} | ||
|
||
dl.stack.Remove(element) | ||
result = element.Value.(T) | ||
return result, nil | ||
} | ||
|
||
// Length returns the number of elements in the stack | ||
func (dl *doublyLinkedList[T]) Len() int { | ||
if dl == nil { | ||
return 0 | ||
} | ||
return dl.stack.Len() | ||
} | ||
|
||
// Empty returns true if stack has no elements and false otherwise. | ||
func (dl *doublyLinkedList[T]) Empty() bool { | ||
if dl == nil { | ||
return true | ||
} | ||
return dl.stack.Len() == 0 | ||
} | ||
|
||
// Clear initializes the underlying storage with a new empty doubly linked list, thus clearing the underlying storage. | ||
func (dl *doublyLinkedList[T]) Clear() { | ||
if dl == nil { | ||
return | ||
} | ||
dl.stack = list.New() | ||
} | ||
|
||
// ToSlice returns the elements of stack as a slice | ||
func (dl *doublyLinkedList[T]) ToSlice() []T { | ||
var result []T | ||
if dl == nil { | ||
return result | ||
} | ||
|
||
for e := dl.stack.Front(); e != nil; e = e.Next() { | ||
result = append(result, e.Value.(T)) | ||
} | ||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Stack Test | ||
// description: based on `geeksforgeeks` description Stack is a linear data structure which follows a particular order in which the operations are performed. | ||
// The order may be LIFO(Last In First Out) or FILO(First In Last Out). | ||
// details: | ||
// Stack Data Structure : https://www.geeksforgeeks.org/stack-data-structure-introduction-program/ | ||
// Stack (abstract data type) : https://en.wikipedia.org/wiki/Stack_(abstract_data_type) | ||
// author [Milad](https://github.com/miraddo) | ||
// see stackarray.go, stacklinkedlist.go, stacklinkedlistwithlist.go | ||
|
||
package stack | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
// TestStackLinkedListWithList for testing Stack with Container/List Library (STL) | ||
func TestStackLinkedListWithList(t *testing.T) { | ||
st := NewDoublyLinkedList[int]() | ||
|
||
t.Run("Stack Push", func(t *testing.T) { | ||
|
||
st.Push(2) | ||
st.Push(3) | ||
|
||
if st.Len() != 2 { | ||
t.Errorf("Expected 2 elements in the stack, found %d", st.Len()) | ||
} | ||
}) | ||
|
||
t.Run("Stack Pop", func(t *testing.T) { | ||
pop, _ := st.Pop() | ||
|
||
if pop != 3 { | ||
t.Errorf("Expected 3 from Pop operation, got %d", pop) | ||
} | ||
|
||
if st.Len() != 1 { | ||
t.Errorf("Expected stack length to be 1 after Pop operation, got %d", st.Len()) | ||
} | ||
}) | ||
|
||
t.Run("Stack Peek", func(t *testing.T) { | ||
st.Push(2) | ||
st.Push(83) | ||
peek, _ := st.Peek() | ||
if peek != 83 { | ||
t.Errorf("Expected value 83 from Peek operation, got %d", peek) | ||
} | ||
}) | ||
|
||
t.Run("Stack Len", func(t *testing.T) { | ||
if st.Len() != 3 { | ||
t.Errorf("Expected stack length to be 3, got %d", st.Len()) | ||
} | ||
}) | ||
|
||
t.Run("Stack Empty", func(t *testing.T) { | ||
if st.Empty() { | ||
t.Error("Stack should not be empty") | ||
} | ||
st.Clear() | ||
if !st.Empty() { | ||
t.Error("Stack is expected to be empty") | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package stack | ||
|
||
type node[T any] struct { | ||
Val T | ||
Next *node[T] | ||
} | ||
|
||
// linkedList implements stack.Interface using a singly linked list as the underlying storage | ||
type linkedList[T any] struct { | ||
top *node[T] | ||
length int | ||
} | ||
|
||
func NewLinkedList[T any]() Interface[T] { | ||
return new(linkedList[T]) | ||
} | ||
|
||
// Push value to the top of the stack | ||
func (ll *linkedList[T]) Push(n T) { | ||
newStack := new(node[T]) | ||
|
||
newStack.Val = n | ||
newStack.Next = ll.top | ||
|
||
ll.top = newStack | ||
ll.length++ | ||
} | ||
|
||
// Pop returns last inserted element and removes it from the underlying storage | ||
// If the stack is empty, ErrStackEmpty error is returned | ||
func (ll *linkedList[T]) Pop() (T, error) { | ||
var element T | ||
if ll.Empty() { | ||
return element, ErrStackEmpty | ||
} | ||
element = ll.top.Val | ||
ll.top = ll.top.Next | ||
ll.length-- | ||
return element, nil | ||
} | ||
|
||
// Empty returns true if stack has no elements and false otherwise. | ||
func (ll *linkedList[T]) Empty() bool { | ||
return ll.length == 0 | ||
} | ||
|
||
// Len returns length of the stack | ||
func (ll *linkedList[T]) Len() int { | ||
return ll.length | ||
} | ||
|
||
// Peek return last inserted element(top of the stack) without removing it from the stack | ||
// If the stack is empty, ErrStackEmpty error is returned | ||
func (ll *linkedList[T]) Peek() (T, error) { | ||
var element T | ||
if ll == nil || ll.length == 0 { | ||
return element, ErrStackEmpty | ||
} | ||
return ll.top.Val, nil | ||
} | ||
|
||
// ToSlice returns the elements of stack as a slice | ||
func (ll *linkedList[T]) ToSlice() []T { | ||
var elements []T | ||
if ll == nil { | ||
return elements | ||
} | ||
|
||
current := ll.top | ||
for current != nil { | ||
elements = append(elements, current.Val) | ||
current = current.Next | ||
} | ||
return elements | ||
} | ||
|
||
func (ll *linkedList[T]) Clear() { | ||
if ll == nil { | ||
return | ||
} | ||
ll.top = nil | ||
ll.length = 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package stack | ||
|
||
import "testing" | ||
|
||
// TestStackLinkedList for testing stack implementation using singly linked list | ||
func TestStack_SinglyLinkedList(t *testing.T) { | ||
st := NewLinkedList[int]() | ||
|
||
st.Push(1) | ||
st.Push(2) | ||
|
||
t.Run("Stack Push", func(t *testing.T) { | ||
result := st.ToSlice() | ||
expected := []int{2, 1} | ||
for x := range result { | ||
if result[x] != expected[x] { | ||
t.Errorf("Expected stack elements to be %v. Current elements: %v", expected, result) | ||
} | ||
} | ||
}) | ||
|
||
t.Run("Stack isEmpty", func(t *testing.T) { | ||
if st.Empty() { | ||
t.Error("Stack shouldn't be emtpy") | ||
} | ||
}) | ||
|
||
t.Run("Stack Length", func(t *testing.T) { | ||
if st.Len() != 2 { | ||
t.Errorf("Expected stack length to be 2, got %d", st.Len()) | ||
} | ||
}) | ||
|
||
st.Pop() | ||
pop, _ := st.Pop() | ||
|
||
t.Run("Stack Pop", func(t *testing.T) { | ||
if pop != 1 { | ||
t.Errorf("Expected 1 from Pop operation, got %d", pop) | ||
} | ||
}) | ||
|
||
st.Push(52) | ||
st.Push(23) | ||
st.Push(99) | ||
t.Run("Stack Peek", func(t *testing.T) { | ||
if val, _ := st.Peek(); val != 99 { | ||
t.Errorf("Expected 99 from Peek operation, got %d", val) | ||
} | ||
}) | ||
} |
Oops, something went wrong.