Data structures decide how your data is stored; algorithms decide what you do with it. Together they’re the difference between a list that scrolls smoothly and one that freezes, and between a search that takes milliseconds and one that takes minutes.
They’re also the backbone of technical interviews. This guide starts with the containers you use every day and works up to the clever structures that power search engines, maps, and blockchains.
The new articles use Swift 5.7-compatible examples and dates from January 2023 through September 2025. Their language features, framework APIs, and pinned dependencies were available by those dates. Existing linked articles keep their original publication dates. The sorting comparison distinguishes the Swift 5.8 documentation guarantee for stable sorting from earlier implementation behavior.
Each topic develops a working implementation or a worked analysis, explains its correctness assumptions and complexity, and includes boundary cases and exercises. Equations and diagrams support the reasoning. The arrays article covers both arrays and dictionaries; the linked-list article develops persistent lists and queues, and the binary-search-tree article includes persistent update semantics. Dedicated hash-table, queue, and trie articles extend those foundations.
Article available Coming soon
1. Measuring Performance
Time and Space Complexity in Swift: Count Work, Copies, and Live Storage
A feed can become slow even when each visible line of Swift looks harmless. A membership test inside a loop, an array...
Big O in Swift: Bounds, Growth Rates, and Amortized Work
A complexity label is a bound on a specified cost function. It becomes misleading when its assumptions disappear: “constant lookup” without hashing...
Analyzing Swift Algorithms: From a Slow Screen to a Defensible Cost Model
A sluggish screen is a symptom, not a complexity class. Before replacing data structures, identify the calculation being repeated, define the required...
2. Elementary Data Structures
Arrays and Dictionaries in Swift
Almost every app is a story about lists and lookups: a feed of posts, a table of settings, a cache keyed by...
Hash Tables in Swift: Collisions, Resizing, and Stable Key Contracts
A hash table uses a key’s hash to narrow a lookup to a small part of its storage. Equality still decides whether...
Swift Sets: Basics and Practical Examples
Swift offers three primary collection types: Arrays, Sets, and Dictionaries, each serving distinct purposes in data management. In this post, we will...
Stacks in Swift: LIFO State, Balanced Delimiters, and Undo
A stack exposes the most recently added item first: last in, first out. That simple rule models unfinished work, nested delimiters, navigation...
Queues in Swift: FIFO Without Repeated Array Shifts
A queue returns items in the order they arrived. That is the right discipline for breadth-first search, pending jobs, and event buffering....
Purely Functional Data Structures in Swift: Persistent Lists and Queues
A persistent data structure keeps earlier versions usable after an update. Here “persistent” describes version preservation, not saving to disk. An editor...
3. Sorting
Comparing Sorting Algorithms in Swift: Stability, Memory, and Real Workloads
Choosing a sorting algorithm starts with a contract: what defines order, what happens to equal keys, how large the input can be,...
Bubble Sort in Swift: Inversions, Early Exit, and a Correctness Invariant
Bubble sort repeatedly swaps adjacent out-of-order elements. Its practical importance is limited, but it offers a clear connection between a local operation,...
Insertion Sort in Swift: Sorted Prefixes and Nearly Sorted Input
Insertion sort maintains a sorted prefix and inserts the next element into that prefix. It is a good example of an adaptive...
Selection Sort in Swift: Minimum Selection and the Cost of Writes
Selection sort repeatedly finds the smallest remaining element and moves it to the next output position. It performs many comparisons but relatively...
Stable Merge Sort in Swift: Divide, Merge, and Account for Storage
Merge sort splits input into smaller regions, sorts them, and merges ordered results. Its reliable O(n log n) comparison bound comes from...
Quicksort in Swift: Three-Way Partitioning and Duplicate Keys
Quicksort partitions a region around a pivot and sorts the remaining regions. Its speed comes from doing useful ordering work during partitioning;...
4. Trees
Binary Trees in Swift: Shape, Traversal, and Expression Evaluation
A binary tree gives each node up to two children. It does not automatically provide fast lookup: a binary search tree adds...
Persistent Binary Search Trees and Tries in Swift
An immutable tree update reconstructs the path to a changed node while reusing untouched branches. That gives the program a new root...
Heaps and Priority Queues in Swift: Maintain the Next Best Item
A priority queue repeatedly returns the next best item according to an ordering. A binary heap supports that operation without keeping the...
AVL Trees in Swift: Rotations, Cached Heights, and Logarithmic Search
A binary search tree is fast only when its height stays small. Inserting sorted keys into an ordinary tree can produce a...
Splay Trees in Swift: Move Accessed Keys to the Root
A splay tree reorganizes itself around accessed keys. After a successful search, the found node becomes the root. After a miss, a...
Tries in Swift: Prefix Search, Deletion, and Unicode Policy
A trie indexes a key by its components rather than comparing the whole key at every search step. For words, each edge...
5. Graphs
Graphs in Swift: Vertices, Edges, and Representation Contracts
A graph represents relationships between entities. A route map, dependency system, social network, and state machine can all use vertices and edges,...
Depth-First Search in Swift: Paths, Cycles, and Topological Order
Depth-first search follows one branch until it can go no farther, then resumes unfinished work. That traversal supports reachability, dependency ordering, and...
Breadth-First Search in Swift: Layers, Shortest Hops, and Multi-Source Search
Breadth-first search explores a graph in layers of increasing edge count. Its queue discipline ensures every vertex at distance d is processed...
Shortest Paths in Swift: Dijkstra, Bellman-Ford, and Weight Assumptions
A shortest-path algorithm minimizes a defined sum of edge weights. Breadth-first search minimizes edge count only when all edges have equal cost....
A* Pathfinding in Swift: Heuristics, Reopening, and Optimality
A* adds a lower-bound estimate of remaining work to the cost already paid. It prioritizes vertices by estimated total route cost, which...
Minimum Spanning Trees in Swift: Kruskal, Union-Find, and Cut Safety
A minimum spanning tree connects every vertex of an undirected connected graph while minimizing total selected edge weight. It is not a...
Using SwiftGraph in Swift: Model the Problem and Verify Library Semantics
A graph library can remove repetitive traversal and storage code, but it cannot choose the graph’s meaning. Direction, vertex identity, weight units,...
6. Advanced Topics
Dynamic Programming in Swift: State, Recurrences, and Reconstructing Decisions
Dynamic programming solves a problem by defining states, expressing each state in terms of smaller states, and reusing their results. A table...
Inverted Indexes in Swift: Tokenization, Posting Lists, and Boolean Search
An inverted index maps a term to the documents containing it. A positional index also records where each occurrence appears, allowing phrase...
Bloom Filters in Swift: Probabilistic Membership with an Error Budget
A Bloom filter answers membership approximately using a bit array. A negative result means an item was not inserted under the filter’s...
HyperLogLog in Swift: Estimate Distinct Counts and Merge Compatible Sketches
Counting distinct values exactly requires remembering which values have appeared. HyperLogLog trades exactness for a compact summary whose size is chosen in...
Merkle Trees in Swift: Commitments, Inclusion Proofs, and Canonical Encoding
A Merkle tree commits to a collection through hashes of its leaves and internal nodes. An inclusion proof lets a verifier check...
Cryptographic Algorithms in Swift: SHA-256, X25519, and Derived Keys
Hashing, key agreement, key derivation, and authenticated encryption solve different problems. SHA-256 produces a deterministic digest. Diffie-Hellman-style agreement lets two private-key holders...
The Fourier Transform in Swift: DFT, Radix-2 FFT, and Sampling
The discrete Fourier transform expresses a finite signal as a combination of frequency components. A fast Fourier transform computes the same result...
Parallel Algorithms and MapReduce in Swift: Partition, Isolate, and Combine
Parallel execution helps when independent work is large enough to repay scheduling, copying, and combination costs. Adding one task per element can...
Linear Programming in Swift: Model Constraints and Solve Small Two-Variable Problems
Linear programming chooses real-valued decision variables to optimize a linear objective while satisfying linear constraints. A model can allocate resources, plan production,...
7. Practice
The best way to learn algorithms is to solve problems with them:
Refresher: Solving Few Problems
After reading the very popular book, Grokking Algorithms, I decided to blog about algorithms and data structures. I find the book is...
Up next
Design Patterns