Introduction to Algorithms and Data Structures in Go
Go (Golang) is a modern compiled programming language developed at Google. It combines the performance of C++ with the simplicity of Python, making it an ideal choice for learning algorithms and data structures. In this article, we will cover fundamental concepts that will help you start writing efficient code in Go.
Understanding data structures and algorithms is a key skill for any developer. They allow you to efficiently organize data and solve problems in an optimal way. Go provides powerful built-in types such as slices and maps, but knowledge of basic structures will help you create more complex solutions.
Basic Data Structures in Go
Arrays and Slices
In Go, arrays have a fixed length, while slices are dynamic. Slices are a more flexible tool and are used most often.
package main
import "fmt"
func main() { // Fixed-length array var arr [5]int = [5]int{1, 2, 3, 4, 5} fmt.Println("Array:", arr)
// Slice — dynamic array slice := []int{10, 20, 30, 40, 50} fmt.Println("Slice:", slice)
// Adding an element to a slice slice = append(slice, 60) fmt.Println("Slice after append:", slice)
// Slice from part of an array subSlice := arr[1:4] fmt.Println("Sub-slice:", subSlice)}Slices in Go are a reference to an underlying array. They contain a pointer to the first element, length, and capacity. This makes them very efficient for working with sequences of data.
Stack in Go
A stack is a data structure that operates on the LIFO (Last In, First Out) principle. In Go, a stack can be easily implemented using a slice.
package main
import ( "fmt" "errors")
type Stack []int
func (s *Stack) Push(v int) { *s = append(*s, v)}
func (s *Stack) Pop() (int, error) { if len(*s) == 0 { return 0, errors.New("stack is empty") } index := len(*s) - 1 element := (*s)[index] *s = (*s)[:index] return element, nil}
func main() { var stack Stack stack.Push(1) stack.Push(2) stack.Push(3) for len(stack) > 0 { val, err := stack.Pop() if err == nil { fmt.Println("Popped:", val) } }}Stacks are used in tree traversal algorithms, bracket checking, undo operations, and expression parsing.
Queue in Go
A queue operates on the FIFO (First In, First Out) principle. In Go, it can be implemented using a slice or a doubly linked list.
package main
import "fmt"
type Queue []int
func (q *Queue) Enqueue(v int) { *q = append(*q, v)}
func (q *Queue) Dequeue() (int, bool) { if len(*q) == 0 { return 0, false } element := (*q)[0] *q = (*q)[1:] return element, true}
func main() { queue := Queue{} queue.Enqueue(10) queue.Enqueue(20) queue.Enqueue(30) for len(queue) > 0 { val, ok := queue.Dequeue() if ok { fmt.Println("Dequeued:", val) } }}Queues are used in task management systems, data buffering, and breadth-first search (BFS) algorithms.
Basic Sorting and Searching Algorithms
Bubble Sort
A simple sorting algorithm that repeatedly steps through the array, comparing adjacent elements and swapping them if they are in the wrong order.
package main
import "fmt"
func bubbleSort(arr []int) { n := len(arr) for i := 0; i < n-1; i++ { for j := 0; j < n-i-1; j++ { if arr[j] > arr[j+1] { arr[j], arr[j+1] = arr[j+1], arr[j] } } }}
func main() { data