Data structures and algorithms are the foundation of every coding interview — and more importantly, of writing code that actually scales. This guide organises all 197 DSA topics on TheCodeForge from arrays to dynamic programming.
Data structures and algorithms have a reputation as interview homework, which undersells them badly. The real return is not passing a round — it is that you stop writing accidentally quadratic code, you recognise when a problem has a known shape, and you can estimate whether an approach will survive contact with production data before you build it.
The subject is also smaller than it looks. A handful of structures and about ten algorithmic patterns cover the overwhelming majority of both interview questions and real engineering problems. What separates people who find this easy is not memory — it is having internalised the trade-off each structure makes.
Choosing a data structure is choosing which operation you want to be fast, because none of them is fast at everything. Reading the table below as a set of trade-offs rather than a set of facts is what makes it usable under pressure.
| Structure | Fast at | Slow at | Real cost |
|---|---|---|---|
| Array / dynamic array | Index access, iteration | Insert or delete in the middle | Contiguous memory — excellent cache locality, which is why it beats linked lists in practice far more often than the complexity table suggests |
| Hash map | Lookup, insert, delete — O(1) average | Ordered traversal | Worst case degrades to O(n) with bad hashing; no ordering guarantee |
| Balanced BST / sorted map | Ordered traversal, range queries, O(log n) lookup | Raw lookup speed versus a hash map | Pointer chasing — worse cache behaviour |
| Heap | Min or max in O(1), insert and extract in O(log n) | Searching for an arbitrary element | Only the extreme is ordered; the rest is not sorted |
| Stack / queue | Push and pop at one or both ends | Any access to the middle | None — the restriction is the point |
| Trie | Prefix lookup in O(length) | Memory | One node per character can be large; compress it if it matters |
| Graph (adjacency list) | Neighbour iteration | Edge existence checks | Use a matrix instead when the graph is dense and small |
Big-O describes how cost grows, not how fast something is. That distinction matters in practice more than the notation itself: an O(n log n) sort routinely beats an O(n) algorithm with a large constant on real input sizes, and an O(n²) loop over twenty elements is entirely fine.
Two habits make the analysis useful rather than ceremonial. Consider space as well as time — a memoisation table that solves a problem in O(n) time and O(n²) space may be the wrong trade. And know that amortised is not worst case: a dynamic array append is O(1) amortised, but the append that triggers a resize copies everything, which matters if you have a latency budget rather than a throughput one.
Most problems are a variation on a short list, and the input's shape usually announces which. Recognising the pattern is the hard part; the implementation is usually mechanical afterwards.
| Pattern | Tell | Typical cost |
|---|---|---|
| Two pointers | A sorted array, or a pair that must sum to a target | O(n) time, O(1) space |
| Sliding window | Longest or shortest contiguous run satisfying a condition | O(n) |
| Binary search | Sorted input, or a monotonic answer space ('smallest x that works') | O(log n) |
| BFS | Shortest path in an unweighted graph or grid | O(V + E) |
| DFS / backtracking | Explore all paths, generate combinations | O(V + E), or exponential when generating |
| Heap | Top k, running median, merge k sorted lists | O(n log k) |
| Dynamic programming | Count the ways, or optimise over choices with overlapping subproblems | O(states × transitions) |
| Union-find | Connectivity, especially as edges arrive over time | Near O(1) per operation with path compression |
Dynamic programming is where most people stall, and it becomes tractable when treated as a procedure rather than a bag of solutions: define the state, write the recurrence, identify base cases, choose an evaluation order. Write the memoised recursion first — it follows directly from the recurrence — and convert to a table only if you need the space saving.
The structures are not abstractions invented for exams; they are what your infrastructure is built from. A database index is a B-tree. An LSM-tree storage engine is heaps and sorted runs. A router's prefix table is a trie. An LRU cache is a hash map plus a doubly-linked list. Git's object store is a Merkle DAG. Consistent hashing — the thing that decides which shard your key lands on — is a sorted structure with binary search.
That is the real argument for learning this properly. It is not that you will implement a B-tree; it is that when your query is slow because the index cannot be used, you will know why.
Every tutorial starts with a plain-English analogy — then real code, then interview questions.
Browse DSA Tutorials →