How to Implement a Stack in Go with Slices

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Setting up the Environment
  4. Implementing a Stack
  5. Example Usage
  6. Recap

Introduction

In this tutorial, we will learn how to implement a stack data structure in Go using slices. A stack is a Last-In-First-Out (LIFO) data structure, where elements are added and removed from the same end, called the top. We will explore the essential operations of a stack, such as push, pop, and peek.

By the end of this tutorial, you will have a clear understanding of how to implement a stack in Go and be able to use it in your own projects.

Prerequisites

To follow along with this tutorial, you should have a basic understanding of the Go programming language. Familiarity with slices and functions will be helpful, but not essential.

Setting up the Environment

Before we begin implementing the stack, make sure you have Go installed on your machine. You can download it from the official Go website (https://golang.org/dl/).

Once you have Go installed, open your favorite text editor or integrated development environment (IDE) to start coding.

Implementing a Stack

To implement a stack, we will define a struct type to represent the stack and associated methods to perform stack operations.

Let’s create a new file called stack.go and start implementing the stack.

package main

import "fmt"

type Stack struct {
  elements []interface{}
}

func (s *Stack) Push(element interface{}) {
  s.elements = append(s.elements, element)
}

func (s *Stack) Pop() interface{} {
  if len(s.elements) == 0 {
    return nil
  }
  index := len(s.elements) - 1
  element := s.elements[index]
  s.elements = s.elements[:index]
  return element
}

func (s *Stack) Peek() interface{} {
  if len(s.elements) == 0 {
    return nil
  }
  return s.elements[len(s.elements)-1]
}

func main() {
  // Testing the stack implementation
  stack := Stack{}

  stack.Push("Apple")
  stack.Push("Banana")
  stack.Push("Cherry")

  fmt.Println(stack.Pop())  // Output: Cherry
  fmt.Println(stack.Pop())  // Output: Banana
  fmt.Println(stack.Peek()) // Output: Apple
}

In the above code, we create a struct type called Stack that contains a slice called elements to store the elements of the stack. We define three methods on the Stack struct: Push, Pop, and Peek.

The Push method appends an element to the end of the elements slice. The Pop method removes and returns the top element of the stack. The Peek method returns the top element of the stack without removing it.

In the main function, we create a new Stack instance called stack and perform some stack operations to test our implementation. We push three elements to the stack, then pop two elements and peek at the top element.

Example Usage

Let’s demonstrate how the stack implementation can be used in a real-world scenario. Suppose we need to validate the brackets in a given string to ensure they are properly nested.

package main

import (
	"fmt"
)

func validateBrackets(input string) bool {
	stack := Stack{}

	for _, char := range input {
		if char == '(' || char == '[' || char == '{' {
			stack.Push(char)
		} else if char == ')' || char == ']' || char == '}' {
			peek := stack.Peek()
			if peek == nil {
				return false
			}
			if (char == ')' && peek != '(') || (char == ']' && peek != '[') || (char == '}' && peek != '{') {
				return false
			}
			stack.Pop()
		}
	}

	return stack.Peek() == nil
}

func main() {
	input1 := "(())"      // Valid
	input2 := "({[]})"    // Valid
	input3 := "({)[]})"   // Invalid
	input4 := "({[})"     // Invalid
	input5 := "())()"     // Invalid

	fmt.Println(validateBrackets(input1)) // Output: true
	fmt.Println(validateBrackets(input2)) // Output: true
	fmt.Println(validateBrackets(input3)) // Output: false
	fmt.Println(validateBrackets(input4)) // Output: false
	fmt.Println(validateBrackets(input5)) // Output: false
}

In this example, we define a function validateBrackets that takes a string input as an argument and uses the stack to validate the brackets. It iterates over each character in the string and checks if it is an opening bracket ((, [, or {) or a closing bracket (), ], or }). If it is an opening bracket, it pushes it onto the stack. If it is a closing bracket, it checks if the stack is empty or if the corresponding opening bracket matches the top element of the stack. If the brackets are properly nested, the stack should be empty at the end.

We test the validateBrackets function with different input strings to verify the correctness of our stack implementation.

Recap

In this tutorial, we learned how to implement a stack data structure in Go using slices. We defined a struct type to represent the stack and associated methods to perform stack operations such as push, pop, and peek. We also explored a real-world example of using the stack to validate brackets in a string.

By understanding and implementing stacks, you now have a powerful data structure at your disposal to solve various problems efficiently. Keep practicing and exploring more about data structures and algorithms to become a better Go programmer.

Happy coding!