diff --git a/datastructures/README.md b/datastructures/README.md new file mode 100644 index 0000000..fabe3c9 --- /dev/null +++ b/datastructures/README.md @@ -0,0 +1,7 @@ +# Basic Data Structures + +These are basic implementations of standard data structures. They are not thread safe implementations. To avoid race conditions you would need to use a mutex (mutual exclusion lock) to lock the data structure before any reads or writes. The `sync` package has a `RWMutex` that can be used. + + +## Example of using Mutex + diff --git a/datastructures/queue.go b/datastructures/queue.go new file mode 100644 index 0000000..271005f --- /dev/null +++ b/datastructures/queue.go @@ -0,0 +1,41 @@ +package datastructures + +import "errors" + +// Queue a First in First out data structure. +type Queue struct { + elements []any +} + +// Enqueue adds and element to the queue +func (q *Queue) Enqueue(el any) { + q.elements = append(q.elements, el) +} + +// Dequeue removes an element from the queue +func (q *Queue) Dequeue() (any, error) { + if q.IsEmpty() { + return nil, errors.New("empty queue") + } + el := q.elements[0] + q.elements = q.elements[1:] + return el, nil +} + +// Peek retrieves a copy of the next element in the queue. +func (q *Queue) Peek() (any, error) { + if q.IsEmpty() { + return nil, errors.New("empty queue") + } + return q.elements[0], nil +} + +// IsEmpty checks if the queue has any elements +func (q *Queue) IsEmpty() bool { + return q.Size() == 0 +} + +// Size checks the size of the queue +func (q *Queue) Size() int { + return len(q.elements) +} diff --git a/datastructures/set.go b/datastructures/set.go new file mode 100644 index 0000000..b8d5390 --- /dev/null +++ b/datastructures/set.go @@ -0,0 +1,91 @@ +package datastructures + +type Set struct { + elements map[any]bool +} + +func (s *Set) Add(el any) { + s.elements[el] = true +} + +func (s *Set) Remove(el any) { + delete(s.elements, el) +} + +func (s *Set) IsEmpty() bool { + return s.Size() == 0 +} + +func (s *Set) Size() int { + return len(s.elements) +} + +func (s *Set) Has(el any) bool { + _, ok := s.elements[el] + return ok +} + +func (s *Set) Difference(set Set) Set { + d := s.Copy() + for k := range d.elements { + if set.Has(k) { + d.Remove(k) + } + } + + return d +} + +func (s *Set) IsSubset(t Set) bool { + for k := range s.elements { + if !t.Has(k) { + return false + } + } + return true +} + +func (s *Set) List() []any { + list := make([]any, s.Size()) + for k := range s.elements { + list = append(list, k) + } + return list +} + +func (s *Set) Copy() Set { + c := NewSet() + for k := range s.elements { + c.Add(k) + } + return c +} + +// NewSet creates a new instance of Set +func NewSet() Set { + return Set{elements: make(map[any]bool)} +} + +// Union determines the OR relationship on all sets under consideration +func Union(sets ...Set) Set { + u := sets[0].Copy() + for _, set := range sets[1:] { + for k := range set.elements { + u.Add(k) + } + } + return u +} + +// Intersection determines the AND relationship of all sets under consideration +func Intersection(sets ...Set) Set { + i := sets[0].Copy() + for k := range i.elements { + for _, set := range sets[1:] { + if !set.Has(k) { + i.Remove(k) + } + } + } + return i +} diff --git a/datastructures/stack.go b/datastructures/stack.go new file mode 100644 index 0000000..e4252f7 --- /dev/null +++ b/datastructures/stack.go @@ -0,0 +1,66 @@ +package datastructures + +import "errors" + +// Stack a Last in First out data structure. +type Stack struct { + elements []any +} + +// Push add an element to the top of the stack +// +// Parameters: +// +// any: an element to add to the top of the stack. +func (s *Stack) Push(el any) { + s.elements = append(s.elements, el) +} + +// Pop removes and returns the top element of the stack. +// +// Returns: +// +// any: The top element of the stack +// +// error: If the stack is found to be empty +func (s *Stack) Pop() (any, error) { + if s.IsEmpty() { + return nil, errors.New("empty stack") + } + el := s.elements[len(s.elements)-1] + s.elements = s.elements[:len(s.elements)-1] + return el, nil +} + +// Peek checks the top item in the stack. +// +// Returns: +// +// any: a copy of the top element +// +// error: An error if the stack is empty +func (s *Stack) Peek() (any, error) { + if s.IsEmpty() { + return nil, errors.New("empty stack") + } + + return s.elements[len(s.elements)-1], nil +} + +// IsEmpty checks if the stack contains any elements. +// +// Returns: +// +// bool: True is the stack is empty. False if the stack contains elements. +func (s *Stack) IsEmpty() bool { + return s.Size() == 0 +} + +// Size checks this size of the stack +// +// Returns: +// +// int: The number of elements on the stack +func (s *Stack) Size() int { + return len(s.elements) +}