Algorithms and Data Structures in Swift: In Practice
Swift is a powerful and intuitive programming language created by Apple for developing iOS, macOS, watchOS, and tvOS applications. However, knowing syntax and frameworks is only half the battle. To write efficient, fast, and scalable applications, you need to understand how algorithms and data structures work. In this article, we will break down key concepts with concrete code examples in Swift. You will learn how to implement a stack, queue, sorting algorithms, and binary search, and where this knowledge is applied in real-world development.
Stack in Swift: LIFO in Action
A stack is a collection that works on the "last in, first out" (LIFO) principle. Imagine a stack of plates: you only take the top one. In iOS, a stack is used, for example, for navigation (UINavigationController) or for undo actions.
Let's implement a stack in Swift using generics:
struct Stack<Element> { private var elements: [Element] = [] mutating func push(_ element: Element) { elements.append(element) } @discardableResult mutating func pop() -> Element? { return elements.popLast() } func peek() -> Element? { return elements.last } var isEmpty: Bool { return elements.isEmpty } var count: Int { return elements.count }}
// Example usagevar stack = Stack<String>()stack.push("First")stack.push("Second")stack.push("Third")
print(stack.pop()!) // Thirdprint(stack.peek()!) // SecondWhere is it applied? In apps for displaying browsing history, in parsers (bracket checking), in graph traversal algorithms (DFS).
Queue: FIFO for Task Processing
A queue works on the "first in, first out" (FIFO) principle. Like a queue in a store: whoever gets in first is served first. In Swift, a queue is often used for task management (DispatchQueue), processing network requests, or animations.
Basic queue implementation:
struct Queue<Element> { private var elements: [Element] = [] mutating func enqueue(_ element: Element) { elements.append(element) } @discardableResult mutating func dequeue() -> Element? { return isEmpty ? nil : elements.removeFirst() } func front() -> Element? { return elements.first } var isEmpty: Bool { return elements.isEmpty } var count: Int { return elements.count }}
// Example usagevar queue = Queue<Int>()queue.enqueue(1)queue.enqueue(2)queue.enqueue(3)
print(queue.dequeue()!) // 1print(queue.front()!) // 2Performance issue: removeFirst() on an array has O(n) complexity because all elements shift. For high performance, use ContiguousArray or a double-ended queue (deque). In real projects, Apple recommends DispatchQueue for multithreading.
Sorting Algorithms: From Bubble Sort to Quick Sort
Sorting is one of the most common operations. Swift has a built-in sort(), but understanding the internal mechanisms will help you choose the optimal algorithm for a specific task.
Bubble Sort — O(n²)
Simple but slow algorithm. Useful for learning, but not for production.
func bubbleSort(_ array: inout [Int]) { guard array.count > 1 else { return } for i in 0..<array.count { var swapped = false for j in 0..<(array.count - 1 - i) { if array[j] > array[j + 1] { array.swapAt(j, j + 1) swapped =