Top 5 Data Structures Every Developer Should Know
Arrays, linked lists, trees, hash maps, graphs — master these five and you'll be ready for almost any coding challenge.
Why Data Structures Are Your Foundation
Every algorithm problem is, at its core, a question about organizing and accessing data efficiently. The data structure you choose determines everything: the time complexity, the code clarity, and often whether the solution is even possible within constraints.
You don't need to know 50 data structures. You need to know 5 deeply — their internals, their trade-offs, and the problem patterns where each one shines.
1. Arrays
The most fundamental structure in all of programming. Elements stored in contiguous memory, accessible by index in O(1) time.
What makes arrays powerful:
- O(1) random access by index
- Cache-friendly — contiguous memory means fewer cache misses
- Simple and intuitive for ordered data
Where arrays struggle:
- Inserting or deleting in the middle requires shifting elements: O(n)
- Fixed size in many languages (dynamic arrays like Python's list handle this, but with occasional O(n) resize cost)
The patterns arrays unlock:
- Two Pointers: One pointer from the left, one from the right. Great for finding pairs, reversing, or partitioning. Classic: "Two Sum II" on a sorted array.
- Sliding Window: A fixed or variable window that slides through the array. Classic: "Maximum Sum Subarray of Size K."
- Prefix Sums: Precompute cumulative sums to answer range sum queries in O(1). Classic: "Subarray Sum Equals K."
If you only master one data structure, make it arrays. Almost every other structure builds on top of array concepts.
2. Hash Maps
The single most useful data structure in interviews. A hash map stores key-value pairs and gives you O(1) average-case time for insert, delete, and lookup.
How it works: A hash function converts a key into an index. That index points to a bucket in an array. Collisions (two keys mapping to the same index) are handled via chaining (linked list at each bucket) or open addressing.
When to reach for a hash map:
- Counting frequencies (character to count)
- Caching computed results (memoization)
- Checking for duplicates in O(n) instead of O(n2)
- Two Sum — store complements as you iterate
The question that unlocks dozens of problems: "Can I precompute some relationship into a hash map, then answer queries in O(1)?"
Hash sets (hash maps without values) are equally useful when you just need fast membership testing — "have I seen this element before?"
3. Stacks and Queues
These two are often overlooked, but they're the key to a surprisingly large category of problems.
Stack — Last In, First Out (LIFO)
Think of a stack of plates. You add to the top, remove from the top.
- O(1) push and pop
- Used for: backtracking, undo systems, expression parsing, DFS
Queue — First In, First Out (FIFO)
Think of a line at a store. First person in is first person out.
- O(1) enqueue and dequeue (with a deque implementation)
- Used for: BFS, task scheduling, sliding window maximum
The Monotonic Stack — a hidden gem:
A stack that maintains elements in sorted order by popping elements that violate the order. Solves "next greater element" and "largest rectangle in histogram" in O(n). Once you see it, you can't unsee it.
4. Trees (Binary Trees & BSTs)
Trees model hierarchical relationships. They're everywhere: file systems, HTML DOM, compiler parse trees, and of course, coding interviews.
Binary Tree basics:
- Each node has at most two children (left and right)
- No inherent ordering
- Traversals: inorder (left-root-right), preorder (root-left-right), postorder (left-right-root)
Binary Search Tree (BST):
- Left child < parent < right child
- O(log n) search, insert, delete when balanced
- O(n) worst case when degenerate (essentially a linked list)
The traversals you must know by heart:
BFS (level-order): Use a queue. Process nodes level by level. Essential for finding shortest paths, checking symmetry, finding the minimum depth.
DFS (recursive or with stack): Go deep before going wide. Three flavors:
- Inorder: gives sorted output from a BST
- Preorder: serialize/copy a tree
- Postorder: delete a tree, evaluate expression trees
The two questions that solve most tree problems:
- What does this function need to return to my parent?
- What information do I need from my children?
Answer those and the recursive solution practically writes itself.
5. Graphs
The most powerful and the most feared. A graph is just nodes (vertices) connected by edges. Trees are actually a special case of graphs (connected, acyclic, directed).
Representations:
- Adjacency list: Each node maps to its list of neighbors — efficient for sparse graphs, most common in interviews
- Adjacency matrix: 2D array — efficient for dense graphs or edge weight lookups
The algorithms you must know:
BFS (Breadth-First Search): Explores neighbors level by level. Guarantees shortest path in unweighted graphs. Use when you need the minimum number of steps to reach something.
DFS (Depth-First Search): Goes as deep as possible before backtracking. Use for connectivity checks, cycle detection, topological sort.
Union-Find (Disjoint Set Union): Efficiently tracks which nodes belong to the same connected component. Near-constant time per operation. Used in Kruskal's algorithm and "number of islands" variants.
Topological Sort: Ordering of nodes such that for every directed edge (u to v), u comes before v. Only possible in DAGs (directed acyclic graphs). Used in course scheduling, build systems, dependency resolution.
The graph mindset: Many problems that don't look like graph problems are secretly graph problems. "Number of islands" is a graph problem. "Word ladder" is a graph problem. "Course schedule" is a graph problem. When you see "connections," "relationships," or "dependencies" — think graph.
How to Practice These Structures
Don't just read about them. For each structure:
- Implement it from scratch (a basic hash map, a BST with insert/search/delete)
- Solve 5–10 problems that rely on that structure
- Identify which problems share the same underlying pattern
After 4–6 weeks of this, you'll find that most new problems feel familiar — not because you've seen them before, but because you recognize the structure they're built on.
Ready to put this into practice?
Practice on CodingBuddyAI →