When to use a graph
Use a graph when you have:
- Things and relationships between them, where one thing can link to many others and back, such as friends, roads, links between web pages or tasks that depend on each other.
- Questions about connection: "how are A and B linked?", "who is within 2 steps of me?", "are these two accounts in the same group?"
- A need for the shortest or cheapest route, such as the fewest stops or the least travel time.
- Ordering with rules, such as "what must happen before what?", or detecting a cycle that makes that impossible.
Use something else when:
- Every item has exactly one parent and the data only goes downwards: use a tree.
- You only look things up by a key: use a hash map.
- Items are just a sequence: use an array or list.
- The data is regular rows with fixed relationships: a database table with joins is usually simpler.
Write the simple parts yourself, borrow the heavy parts. An adjacency list and a BFS are short enough to write by hand. For weighted shortest paths, very large graphs or analysis such as finding communities, use a tested library (see the real-world section).
How a graph works
A graph is a set of things and the links between them. The things are called nodes (or vertices). The links are called edges. That is all a graph needs:
A graph is nodes plus edges. Every edge joins two nodes, and there is no root, no "left" or "right", and no rule against going round in circles.
Friends on a social network, junctions on a road map and steps in a build are all graphs. A binary search tree is a graph too, just a very tidy one: it has a root, one route between any two nodes, and no cycles. Graphs drop those restrictions, which is why they can describe so many real situations.
Words you will meet:
- Neighbour: a node you can reach along one edge.
- Degree: how many neighbours a node has.
- Path: a list of nodes where each one is joined to the next. Its length is the number of edges.
- Cycle: a path that comes back to where it started.
- Connected: there is a path between every pair of nodes. A graph that is not connected has separate "islands".
- Directed: edges have a direction, like "follows" on a social network. In an undirected graph, an edge works both ways, like friendship.
- Weighted: edges carry a number, such as travel time.
Try it
Pick a method and run it. Watch which node is looked at next, and how the queue (BFS) or the path (DFS) changes.
Graph traversal
Step 1 of 38 · Press Space to play, arrow keys to stepQueue (front first): A
Start at A: put it in the queue.
- visited:
- 0
- edgesChecked:
- 0
- queue:
- 1
visited = nodes finished or in progress. edgesChecked = times an edge was looked at from one end.
Things to try:
- Keep Friend network and BFS, start at
A, and set Look for toH. BFS findsA → B → E → H, which is 3 edges. - Switch to DFS and look for
Hagain. DFS findsA → B → D → G → E → C → F → H, which is 7 edges. It dives deep and takes the first route it finds, not the shortest. - Choose Two islands, start at
Aand visit everything.D,EandFare never visited, because no edge leads to them fromA.
Graph operations: store, traverse and find a route
Store it. The usual choice is an adjacency list: for each node, keep the list of its neighbours. For an undirected edge, add each end to the other's list. It uses memory in proportion to the nodes and edges, and it makes "list the neighbours" fast.
Traverse it. To visit every node you can reach from a start node, keep a visited set so you never go round a cycle forever, and a to-do list of nodes still to explore. The two classic ways differ only in which node you take from the to-do list next:
| Breadth-first search (BFS) | Depth-first search (DFS) | |
|---|---|---|
| To-do list | Queue: take the oldest node | Stack (or recursion): take the newest node |
| Order | Level by level: all neighbours, then their neighbours | Down one branch as far as it goes, then back up |
| Fewest-edges route | Always finds one | Not guaranteed |
| Memory | Can hold a whole level at once | Holds the current path |
| Good for | Shortest route, "within k steps" | Cycles, ordering tasks, exploring everything, puzzles |
Find a route. Run BFS from the start and remember, for each node, which node you came from. When you reach the goal, follow those links back to the start. In an unweighted graph, that route has the fewest edges.
Two interview facts. Both BFS and DFS look at each node once and each edge a fixed number of times, so both are O(V + E). And if edges have different costs, BFS is not enough: you need Dijkstra's algorithm.
Graph time complexity
V is the number of nodes and E is the number of edges. This table assumes an adjacency list.
| Operation | Typical graph | Worst case |
|---|---|---|
| Add a node | O(1) | O(1) |
| Add an edge | O(1) | O(1) |
| Is there an edge between A and B? | O(degree of A) | O(V) |
| List the neighbours of A | O(degree of A) | O(V) |
| BFS or DFS over the whole graph | O(V + E) | O(V + E) |
| Fewest-edges route (BFS) | O(V + E) | O(V + E) |
| Memory | O(V + E) | O(V²) |
The worst case happens in a dense graph, where almost every node is joined to every other, so E grows like V². Most real graphs are sparse (each node has few neighbours compared with the total), which is why adjacency lists are the usual choice.
Graphs vs other data structures
The right choice depends on what you do most. Here is the same set of jobs done with a graph and with the structures you already know. V is the number of nodes and E the number of edges.
| What you need | Graph | Tree | Hash map | Linked list |
|---|---|---|---|---|
| Items linked to many others, both ways | Yes | No, one parent each | Not by itself | No, one "next" each |
| Fewest-edges route between two items | BFS, O(V + E) | The only route, found in O(n) | Not possible | O(n) walk |
| What must come before what | Topological order, O(V + E) | Parents before children only | Not possible | The list order only |
| Cycles allowed | Yes | No | n/a, it has no links | Only if you break the rules |
| Find one item by its key | Needs a hash map beside it | O(log n) if ordered and balanced | O(1) average | O(n) |
The bold cells show where each one wins. A tree is a graph with no cycles and exactly one route between any two nodes. A linked list is a graph where each node has one "next". The graph is the right choice once those limits get in the way, and the wrong one when all you need is a key lookup.
Three ways to store a graph
Once you choose a graph, there are three common ways to store it. This is the same job done three ways.
| What you need | Adjacency list | Adjacency matrix | Edge list |
|---|---|---|---|
| Is there an edge between A and B? | O(degree of A) | O(1) | O(E) |
| List the neighbours of A | O(degree of A) | O(V) | O(E) |
| Add an edge | O(1) | O(1) | O(1) |
| Remove an edge | O(degree of A) | O(1) | O(E) |
| Walk the whole graph (BFS or DFS) | O(V + E) | O(V²) | O(V · E) |
| Memory | O(V + E) | O(V²) | O(E) |
An adjacency matrix is a V by V grid where cell (A, B) says whether the edge exists. An edge list is just a list of pairs. The matrix is best when the graph is dense or you check single edges all the time. The edge list is best for simply storing or sorting edges. For everything else, use the adjacency list.
How to explain graphs in an interview
- Start with the model: "nodes and edges, directed or undirected, weighted or not." Ask which one the question means.
- Say how you will store it: "an adjacency list, so memory is O(V + E)."
- State the complexity in terms of V and E, not n.
- Say you will keep a visited set, because graphs can have cycles.
- Name the choice: "BFS if I need the fewest edges, DFS if I just need to explore or order things, Dijkstra if edges have costs."