Implementing a Queue in Go
💡 Queue
A Queue is a linear data structure that follows a particular order in which operations are performed. The order is First In First Out (FIFO).
Queues are used when you want to have access to elements in a First-In-First-Out manner (FIFO). They're commonly used to handle asynchronous data transfers (like printing documents on a printer), or in scenarios that involve a processing order, such as serving requests on a single shared resource like a printer, CPU task scheduling, etc.
👨🏫 Refer my previous post about Data structures, if you are new to Data structures.
Overview
QUEUE
- 📦 items: QUEUE (items)
- 🚦 methods: ENQUEUE (T), DEQUEUE, FRONT, BACK, LENGTH, TRAVERSE
- ⚡️ extra: ENQUEUE-FRONT, DEQUEUE-BACK, REVERSE
⭐️ In here, we use Go Generics and any data type. You don’t need to have a prior knowledge of Go Generics syntaxes as this is a good example of usage of Generics and a good opportunity to get familiarize with Go Generics syntaxes.
Let’s get started.
Implementation
Queue
type Queue[T any] struct {
items []T
}
Factory
func New[T any]() *Queue[T] {
return &Queue[T]{}
}
Enqueue
func (q *Queue[T]) Enqueue(v T) {
q.items = append(q.items, v)
}
Dequeue
func (q *Queue[T]) Dequeue() (T, error) {
var v T
if len(q.items) == 0 {
return v, ErrEmptyQueue
}
v = q.items[0]
q.items = q.items[1:]
return v, nil
}
var ErrEmptyQueue = errors.New("empty queue")
Front
func (q *Queue[T]) Front() (T, error) {
var v T
if len(q.items) == 0 {
return v, ErrEmptyQueue
}
return q.items[0], nil
}
// var ErrEmptyQueue = errors.New("empty queue")
Back
func (q *Queue[T]) Back() (T, error) {
l := len(q.items)
var v T
if l == 0 {
return v, ErrEmptyQueue
}
return q.items[l-1], nil
}
// var ErrEmptyQueue = errors.New("empty queue")
Length and Traverse
func (q *Queue[T]) Length() int {
return len(q.items)
}
func (q *Queue[T]) String() (str string) {
if len(q.items) == 0 {
return
}
for _, v := range q.items {
str = fmt.Sprintf("%s\n%v", str, v)
}
return
}
⚡️ Let’s see how to implement extra functionalities which are not directly related to this data structure.
Enqueue Front
func (q *Queue[T]) EnqueueFront(v T) {
q.items = append([]T{v}, q.items...)
}
Dequeue Back
func (q *Queue[T]) DequeueBack() (T, error) {
l := len(q.items)
var v T
if l == 0 {
return v, ErrEmptyQueue
}
v = q.items[l-1]
q.items = q.items[:l-1]
return v, nil
}
// var ErrEmptyQueue = errors.New("empty queue")
Reverse
func (q *Queue[T]) Reverse() {
l := len(q.items)
if l < 2 {
return
}
for x, y := 0, l-1; x < y; x, y = x+1, y-1 {
q.items[x], q.items[y] = q.items[y], q.items[x]
}
}
⭐️ To practice further, add following new methods to the queue
HAS : to verify the value already exists in the queue
REMOVE: to remove the value if exists in the queue
Refer singly linked list data structure and implement a queue using it.