DEV Community

german9304
german9304

Posted on

1 1

Let's build a Queue with golang

Queue

Golang is a great language because it is simple to learn and it's fast compare to other languages.

Here we will build a linear data structure called queue,
Queues are FIFO (first in first out)

For example: a waiting row of people to pay it is a que because the person who comes first pays first and etc.

There are different ways to build a queue, you have arrays, or linkedlists and even stacks. For this implementation I used a linkedlist.

Let's begin:

Node

We need some way to create our nodes:

package node

type Node struct {
    item int
    next *Node
}

// Init Node
func New(item int) *Node {
    return &Node{item, nil}
}

func (n *Node) Item() int {
    return n.item
}

func (n *Node) Next() *Node {
    return n.next
}

func (n *Node) SetItem(item int) int {
    n.item = item
    return item
}

func (n *Node) SetNext(nextNode *Node) *Node {
    n.next = nextNode
    return n.next
}

Methods implemented are:

  • **Item*: returns item from node
  • Next: return next element
  • SetItem: sets item to current node
  • SetNext: sets next element

LinkedList

1) First step is to create the linked list:

 package linkedList

import (
    "fmt"
    "stackqueue/node"
    it "stackqueue/iterator"
)


type iterator struct {
    current *node.Node
}

func (it *iterator) Next() *node.Node {
    current := it.current
    it.current = it.current.Next()
    return current
}

func (it *iterator) HasNext() bool {
    if it.current == nil {
        return false
    }

    return true
}

type LinkedList struct {
    head     *node.Node
    current  *node.Node
    length   int
}

func (li *LinkedList) Iterator() it.IIterator {
    head := li.head
    return &iterator{head}
}


func New(head, current *node.Node) *LinkedList {
    return &LinkedList{nil, nil, 0}
}

func (li *LinkedList) Head() *node.Node {
    return li.head
}

// Prints elements from the list
func (li *LinkedList) Print() {
    head := li.head
    for head != nil {
        fmt.Printf("%v\n", head.Item())
        head = head.Next()
    }
}

// Inserts at front of the list
func (li *LinkedList) Insert(item int) *node.Node {
    newNode := node.New(item) // init node
    if li.head == nil {
        li.head = newNode
        li.current = newNode
        li.length++
        return newNode
    }

    newNode.SetNext(li.current)
    li.current = newNode
    li.head = newNode
    li.length = li.length + 1
    return newNode
}

// Removes an element from front of the list
func (li *LinkedList) RemoveFront() *node.Node {
    head := li.head
    if head != nil {
        nextNode := head.Next()
        li.head = nextNode
        head = nil
    }
    return nil
}

This go package implements the link list so we can use it on our Queue structure.

Methods implemented are:

  • New: initializes the linkedlist
  • Append: appends a new item at the end to the list
  • RemoveFront: removes an element from the front of the list
  • Head: returns the front of the list

We need some testing and golang has useful tools to testing,
to test a package we just need to create a file with the name of the file that you are testing and have _test at the end for instance: filename_test.

LinkedList Testing

 package linkedList

import (
    // "log"
    "fmt"
    "testing"
    it "stackqueue/iterator"
)

func TestInsert(t *testing.T) {
    expectedRoot := 10
    li := New(nil, nil)
    li.Insert(34)
    li.Insert(44)
    li.Insert(10)

    item := li.Head().Item()
    if item != expectedRoot {
        t.Errorf("got %v , expected %v \n", item, expectedRoot)
    }
}

func TestAppend(t *testing.T) {
    li := New(nil, nil)
    li.Append(32)
    li.Append(50)
    li.Append(100)

    head := func() int {
        return li.Head().Item()
    }

    if head() != 32 {
        t.Errorf("got %v, expected %v  \n", head(), 32)
    }

    li.RemoveFront()

    if head() != 50 {
        t.Errorf("got %v, expected %v  \n", head(), 50)
    }

    fmt.Println("iterator append")
    var iter it.IIterator = li.Iterator()
    for iter.HasNext() {
        fmt.Printf("%v\n", iter.Next().Item())
    }
    fmt.Println("iterator append")
}

func TestRemoveFront(t *testing.T) {
    numbers := []int{1, 2, 3, 4, 5, 6}
    li2 := New(nil, nil)

    if li2.RemoveFront() != nil {
        t.Errorf("should be nil")
    }


    li := New(nil, nil)
    for _, number := range numbers {
        li.Insert(number)
    }
    li.RemoveFront()

    // New Head 
    if got := li.Head().Item(); got != 5 {
        t.Errorf("got %v , expected %v \n", got, 5)
    }
    var iter it.IIterator = li.Iterator()
    for iter.HasNext() {
        fmt.Printf("%v\n", iter.Next().Item())
    }
}


func ExamplePrint() {
    numbers := []int{1, 2, 3, 4, 5, 6}
    li := New(nil, nil)
    for _, number := range numbers {
        li.Insert(number)
    }
    li.Print()
    // output:
    // 6
    // 5
    // 4 
    // 3
    // 2
    // 1
}

Queue

Now that we have the linkedList we can implement the queue.

 package queue

import (
    "stackqueue/linkedList"
    "stackqueue/node"
    it "stackqueue/iterator"
)


type IQueue interface {
    Enqueue(item int) *node.Node
    Dequeue() *node.Node
    Peek() *node.Node
    Iterator() it.IIterator
}

type Queue struct {
    li *linkedList.LinkedList
}


func New() *Queue {
    list := linkedList.New(nil, nil)
    return &Queue{list}
}

func (q *Queue) Iterator()  it.IIterator {
    return q.li.Iterator()
}

// Top of the list
func (q *Queue) Peek() *node.Node {
    return q.li.Head()
}
// Enqueues element
func (q *Queue) Enqueue(item int) *node.Node {
    newNode := q.li.Append(item)
    return newNode
}

// Dequeue element
func (q *Queue) Dequeue() *node.Node {
    removedNode := q.li.RemoveFront()
    return removedNode
}

Methods implemented are:

  • New: initializes the queue
  • Enqueue: appends an element to the front
  • Dequeue: removes the first element from the list
  • Peek: returns first element from the list

Queue Testing

package queue

import (
    "testing"
    "fmt"
)

// Queue test
func TestQueue(t *testing.T) {
    var queue IQueue = New()
    queue.Enqueue(32)
    queue.Enqueue(40)
    queue.Enqueue(100)

    peek := queue.Peek().Item()
    if peek != 32 {
        t.Errorf("got %v expected \n", peek)
    }

    iter := queue.Iterator()
    for iter.HasNext() {
        fmt.Printf("item %v \n", iter.Next().Item())
    }
}

func TestDequeue(t *testing.T) {
    var queue IQueue = New()
    queue.Enqueue(32)
    queue.Enqueue(40)
    queue.Enqueue(100)
    queue.Enqueue(2)

    queue.Dequeue()

    fmt.Println("iterator Dequeue")
    iter := queue.Iterator()
    for iter.HasNext() {
        fmt.Printf("item %v \n", iter.Next().Item())
    }
    fmt.Println("iterator Dequeue")

    peek := queue.Peek()
    if peek.Item() != 40 {
        t.Errorf("wrong dequeue")
    }
    queue.Dequeue()

    peek = queue.Peek()
    if peek.Item() != 100 {
        t.Errorf("wrong dequeue")
    }
}

Queues are a great and fundamental data structures to learn. Fundamentals are good to learn and have a better ida of it.

Thank you for reading the post, I will implement the stack and give a better explanation of what is a linked list on my next posts.

Let me know what you think, thank you again!.

source code:

Data Structures

  • Linked Lists
  • Binary Search Tree
  • queue
  • stack

golang

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

While many AI coding tools operate as simple command-response systems, Qodo Gen 1.0 represents the next generation: autonomous, multi-step problem-solving agents that work alongside you.

Read full post

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay