Stacks in Go: Introduction and Practical Applications

Introduction

Greetings, Space Explorer! Today, we're drawing back the curtains on Stacks, a crucial data structure. Imagine a stack like a pile of dishes: you add a dish to the top (Last In) and take it from the top (First Out). This Last-In, First-Out (LIFO) principle exemplifies the stack. In Go, stacks can be implemented using slices, which offer a flexible way to store and manipulate elements. This lesson will illuminate the stack data structure, its operations, and its applications in Go. Are you ready to start?

Utilizing Stacks in Go

To create a stack in Go, we can define a custom Stack struct with a slice as an internal storage. To perform the push operation, we use the append method to add an element to the slice's end. For the pop operation, we slice out the last element, simulating the removal of the "top" element in a stack. Here's how it looks:

package main

import (
    "fmt"
)

type Stack struct {
    items []string
}

func (s *Stack) Push(item string) {
    s.items = append(s.items, item)
}

func (s *Stack) Pop() string {
    if len(s.items) == 0 {
        return ""
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item
}

func main() {
    stack := Stack{}

    // Push operations
    stack.Push("John")
    stack.Push("Mary")
    stack.Push("Steve")

    // Pop operation removes 'Steve'
    stack.Pop()
    fmt.Println(stack.items) // Outputs: [John Mary]
}

In the example provided, we add (push) John, Mary, and Steve onto the stack and then remove (pop) Steve from the stack.

Advanced Stack Operations

Stack operations in Go go beyond just push and pop. For example, to verify if a stack is empty, we check if the length of the items slice is 0. To peek at the top element of the stack without popping it, we access the last element of the slice.

Here's an example:

package main

import (
    "fmt"
)

type Stack struct {
    items []string
}

func (s *Stack) Push(item string) {
    s.items = append(s.items, item)
}

func (s *Stack) Pop() string {
    if len(s.items) == 0 {
        return ""
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item
}

func (s *Stack) Peek() string {
    if len(s.items) == 0 {
        return ""
    }
    return s.items[len(s.items)-1]
}

func (s *Stack) IsEmpty() bool {
    return len(s.items) == 0
}

func main() {
    stack := Stack{}
    stack.Push("Steve")
    stack.Push("Sam")

    fmt.Println(stack.Peek()) // Outputs: Sam

    fmt.Println(stack.IsEmpty()) // Outputs: false
    stack.Pop()                 // Remove 'Sam'
    stack.Pop()                 // Remove 'Steve'
    fmt.Println(stack.IsEmpty()) // Outputs: true
}

In this example, Sam is added (pushed), and then the topmost stack element, which is Sam, is accessed (peeked at) without removal. Next, we verify if the stack is empty using the IsEmpty method, which checks if the stack has no elements. The output will be false because the stack is not empty at this point. We then perform two Pop operations to remove Sam and then Steve from the stack. After these Pop operations, when we check IsEmpty again, it will output true, indicating that the stack is now empty since all elements have been removed.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal