How to Queue Implementation in Golang

Jay Singh Feb 02, 2024
  1. Queue Implementation Using slice in Golang
  2. Queue Implementation Using container/list in Golang
How to Queue Implementation in Golang

A queue, like a stack, is a typical data structure that arranges things in a logical order. A queue employs the FIFO(First In First Out) mechanism, in which the first thing enqueued is also the first to be dequeued.

You can create a basic Queue in Golang by:

  1. Slice
  2. Container/List package

Queue Implementation Using slice in Golang

Dequeue and enqueue actions can be conducted as follows since a queue follows a FIFO(First-In-First-Out) structure:

  1. To enqueue, use the built-in add function.
  2. To dequeue, slice off the initial piece.

Example 1:

package main

import "fmt"

type StringQueue struct {
	queue []string
}

func (q *StringQueue) Enqueue(s string) {
	q.queue = append(q.queue, s)
}

func (q *StringQueue) Top() string {
	return q.queue[0]
}

func (q *StringQueue) Dequeue() string {
	temp := q.queue[0]
	q.queue = q.queue[1:]
	return temp
}

func (q *StringQueue) Empty() bool {
	return len(q.queue) == 0
}

func main() {
	fmt.Println("Queues")
	queue := StringQueue{make([]string, 0)}
	(&queue).Enqueue("Item 1")
	(&queue).Enqueue("Item 2")
	fmt.Println("Top:", (&queue).Top())
	fmt.Println("Dequeued", (&queue).Dequeue())
	fmt.Println("New Top:", (&queue).Top())
	fmt.Println("Empty?", (&queue).Empty())
	fmt.Println("Dequeued", (&queue).Dequeue())
	fmt.Println("Empty now?", (&queue).Empty())
}

Output:

Queues
Top: Item 1
Dequeued Item 1
New Top: Item 2
Empty? false
Dequeued Item 2
Empty now? true

Example 2:

package main

import (
	"fmt"
	"sync"
)

type customQueue struct {
	queue []string
	lock  sync.RWMutex
}

func (c *customQueue) Enqueue(name string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.queue = append(c.queue, name)
}

func (c *customQueue) Dequeue() error {
	if len(c.queue) > 0 {
		c.lock.Lock()
		defer c.lock.Unlock()
		c.queue = c.queue[1:]
		return nil
	}
	return fmt.Errorf("Pop Error - Queue is empty")
}

func (c *customQueue) Front() (string, error) {
	if len(c.queue) > 0 {
		c.lock.Lock()
		defer c.lock.Unlock()
		return c.queue[0], nil
	}
	return "", fmt.Errorf("Peep Error - Queue is empty")
}

func (c *customQueue) Size() int {
	return len(c.queue)
}

func (c *customQueue) Empty() bool {
	return len(c.queue) == 0
}

func main() {
	customQueue := &customQueue{
		queue: make([]string, 0),
	}

	fmt.Printf("Enqueue: 1\n")
	customQueue.Enqueue("1")
	fmt.Printf("Enqueue: 2\n")
	customQueue.Enqueue("2")
	fmt.Printf("Len: %d\n", customQueue.Size())

	for customQueue.Size() > 0 {
		frontVal, _ := customQueue.Front()
		fmt.Printf("Front: %s\n", frontVal)
		fmt.Printf("Dequeue: %s\n", frontVal)
		customQueue.Dequeue()
	}
	fmt.Printf("Len: %d\n", customQueue.Size())
}

Output:

Enqueue: 1
Enqueue: 2
Len: 2
Front: 1
Dequeue: 1
Front: 2
Dequeue: 2
Len: 0

Queue Implementation Using container/list in Golang

We can use a dynamic data structure linked list to avoid memory leaks.

Example 1:

package main

import (
	"container/list"
	"fmt"
)

func main() {
	// new linked list
	queue := list.New()

	// Simply append to enqueue.
	queue.PushBack(10)
	queue.PushBack(20)
	queue.PushBack(30)

	// Dequeue
	front := queue.Front()
	fmt.Println(front.Value)
	// This frees up memory and prevents memory leaks.
	queue.Remove(front)
}

Output:

10

Example 2:

package main

import (
	"container/list"
	"fmt"
)

type customQueue struct {
	queue *list.List
}

func (c *customQueue) Enqueue(value string) {
	c.queue.PushBack(value)
}

func (c *customQueue) Dequeue() error {
	if c.queue.Len() > 0 {
		ele := c.queue.Front()
		c.queue.Remove(ele)
	}
	return fmt.Errorf("Pop Error: Queue is empty")
}

func (c *customQueue) Front() (string, error) {
	if c.queue.Len() > 0 {
		if val, ok := c.queue.Front().Value.(string); ok {
			return val, nil
		}
		return "", fmt.Errorf("Peep Error: Queue Datatype is incorrect")
	}
	return "", fmt.Errorf("Peep Error: Queue is empty")
}

func (c *customQueue) Size() int {
	return c.queue.Len()
}

func (c *customQueue) Empty() bool {
	return c.queue.Len() == 0
}

func main() {
	customQueue := &customQueue{
		queue: list.New(),
	}
	fmt.Printf("Enqueue: A\n")
	customQueue.Enqueue("A")
	fmt.Printf("Enqueue: B\n")
	customQueue.Enqueue("B")
	fmt.Printf("Size: %d\n", customQueue.Size())
	for customQueue.Size() > 0 {
		frontVal, _ := customQueue.Front()
		fmt.Printf("Front: %s\n", frontVal)
		fmt.Printf("Dequeue: %s\n", frontVal)
		customQueue.Dequeue()
	}
	fmt.Printf("Size: %d\n", customQueue.Size())
}

Output:

Enqueue: A
Enqueue: B
Size: 2
Front: A
Dequeue: A
Front: B
Dequeue: B
Size: 0