Data Structures & Algorithms Tutorials
Data structures and algorithms in Java 25 — arrays and lists, stacks and queues, hash tables, trees, heaps, tries and graphs, with recursion, sorting, searching, dynamic programming and greedy algorithms. Every implementation is a real compiled file with assertions behind it, not a snippet.
- Depth-First SearchFollow one path to its end, then back up and try the next. The same code as BFS with the queue swapped for a stack — the traversal strategy IS the container. Recursive and iterative forms, cycle detection, and how to choose between DFS and BFS.
- Breadth-First SearchExplore level by level using a queue — and get the shortest path in an unweighted graph for free, which no other traversal does. Reconstructing the path, why you mark visited on enqueue rather than dequeue, and where BFS stops being the right tool.
- GraphsVertices and edges — the structure behind social networks, maps, dependencies and package managers. Directed against undirected, weighted against unweighted, and why an adjacency list beats an adjacency matrix on almost every real graph.
- TriesA prefix tree: one node per character, words spelled out along the paths. Why it is the wrong choice for exact lookup — a HashSet is simpler and faster — and the right one for autocomplete and every other prefix question a set cannot answer.
- Priority QueuesA queue that serves by priority rather than by arrival. What Java's PriorityQueue is underneath, the comparator that decides min-heap or max-heap, the k-largest pattern that beats sorting, and the iteration order that is not sorted and surprises everyone.
- HeapsA tree stored in a flat array with no references at all, kept ordered just enough that the minimum is always at index 0. Sift up, sift down, and why building a heap from an array is O(n) rather than O(n log n) — a genuinely counter-intuitive result.
- Trees and Binary Search TreesThe BST invariant and the O(log n) it buys — but only while the tree stays balanced, and inserting sorted data makes it a linked list in disguise. All four traversals, why in-order comes out sorted, and deletion with two children, the case everyone skips.
- Quick SortPartition around a pivot and recurse. Sorts in place and is usually the fastest in practice, but has an O(n^2) worst case — and the input that triggers it is the already-sorted array you are most likely to be handed. Median-of-three, and the recursion trick that caps the stack at O(log n).
- Merge SortSplit in half, sort each half, merge. O(n log n) in every case and stable, at the cost of O(n) extra space. Why stability is decided by a single <= in the merge, why the buffer should be allocated once, and why Java sorts objects this way.
- Binary SearchHalve the search space every comparison: O(log n), a billion elements in thirty steps. Also the three ways it is habitually got wrong — the midpoint overflow that was in the JDK for nine years, the infinite loop, and the boundary — plus lowerBound, the variant that is actually useful.
- Greedy AlgorithmsTake the best-looking option at each step and never reconsider. Fast, simple, and correct only when the greedy choice property holds — with a worked case where greedy returns three coins and dynamic programming returns two, so you can see it fail.
- Dynamic ProgrammingSolve each subproblem once and remember the answer. The two conditions that have to hold, top-down memoisation versus bottom-up tables, and the jump from O(2^n) to O(n) on Fibonacci. Plus coin change, knapsack, LCS and Kadane's algorithm.
- Divide and ConquerSplit the problem into independent subproblems, solve each, combine. The word doing the work is independent — that is exactly what separates this from dynamic programming. Fast exponentiation, and counting inversions for free inside a merge.
- RecursionA method that calls itself on a smaller version of the same problem. The base case and the progress towards it, what the call stack is really doing, why StackOverflowError is a message rather than a mystery, and when a loop is the better answer.
- Hash TablesTurn the key into an array index and go straight there. Separate chaining, the load factor, why resizing has to rehash rather than copy, what a bad hashCode does to your O(1), and the equals/hashCode contract that breaks lookups when you get it wrong.
- QueuesFirst in, first out. Written as a circular buffer, because the obvious version — shift everything down on dequeue — is O(n) and is the standard way a hand-rolled queue goes wrong. Plus the growth bug that only appears after the buffer has wrapped.
- StacksLast in, first out — everything happens at one end, so everything is O(1). Building one on an array, the balanced-brackets problem that is the reason interviewers ask about stacks, why the call stack is one, and why you should never use java.util.Stack.
- Linked ListsNodes joined by references. O(1) at the front where an array is O(n), O(n) for random access where an array is O(1) — the trade in both directions. Reversing a list in one pass, Floyd's cycle detection, and why the tail reference matters.
- ArrayList — Building a Growable ArrayArrayList with the lid off — an array, a size, and a resize when it fills up. Why doubling makes add() amortised O(1) while growing by one makes n adds O(n^2), what the resize actually costs, and the null that stops a removed element leaking.
- ArraysThe structure everything else is built on: a fixed-length block of memory where index arithmetic makes any element reachable in one step. What that buys you, what it costs on insert and delete, and why the fixed length is the whole problem.
- Omega, Theta and the Rest of the NotationBig O is an upper bound, Omega is a lower bound and Theta is both at once. What each one actually claims, why saying an algorithm is O(n^2) does not mean it is slow, and the difference between a bound and a case that people conflate constantly.
- Big O NotationHow an algorithm's cost grows as the input grows — the only performance question that survives a change of hardware. The common classes from O(1) to O(2^n), how to read a complexity off a loop, why constants are dropped, and the difference between time and space complexity.
- Memory — Why Structures Have Different SpeedsThe stack, the heap, and why an array of a million ints can be faster to scan than a linked list of a million ints even though both are O(n). Contiguous memory, cache lines, pointer chasing, and what a Java object reference really costs.
- What a Data Structure Actually IsA data structure is a decision about how to lay data out in memory, and an algorithm is a decision about how to walk it. Why there is no best structure, the four questions that pick one, and the Java collection each choice maps onto.
- Data Structures & Algorithms – Get StartedStart here. What this track covers and in what order, why it is written in Java 25, and how to run every example yourself with nothing but a JDK — no build tool and no dependencies. Also the one habit that separates people who can answer these questions from people who have only read about them.