Graph theory
Subgraph enumeration
Combinatorics
Network analysis
Computational mathematics

Subgraph enumeration

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Subgraph enumeration means listing all subgraphs of a graph that satisfy some pattern or property. The topic sounds broad because it is broad: "enumerate all triangles," "enumerate all connected subgraphs of size k," and "enumerate all maximal cliques" are all subgraph-enumeration problems, but they require different algorithms.

Start by Defining the Target

Before choosing an algorithm, clarify what you want to enumerate:

  • induced or non-induced subgraphs
  • connected subgraphs or arbitrary subsets
  • exact pattern matches such as triangles or paths
  • maximal structures such as maximal cliques

That definition changes both correctness and complexity.

For example, enumerating all k-vertex subsets is easy to describe but often useless because most of those subsets are not connected or do not match the pattern you care about.

Why Enumeration Gets Expensive Fast

Graphs grow combinatorially. Even modest graphs contain many possible vertex subsets, and subgraph isomorphism is computationally hard in general.

That is why practical algorithms rely on pruning:

  • enforce an ordering on vertices
  • stop exploring branches that cannot become valid answers
  • specialize to the pattern you care about

General-purpose "enumerate every possible subgraph" is usually the wrong mental model.

Example: Enumerating All Triangles

Triangles are one of the simplest useful cases. A triangle is a 3-node clique, so we can enumerate them by checking common neighbors in an ordered way.

python
1def enumerate_triangles(graph):
2    triangles = []
3    nodes = sorted(graph)
4
5    for i, u in enumerate(nodes):
6        for v in graph[u]:
7            if v <= u:
8                continue
9            common = graph[u].intersection(graph[v])
10            for w in common:
11                if w > v:
12                    triangles.append((u, v, w))
13
14    return triangles
15
16
17graph = {
18    1: {2, 3, 4},
19    2: {1, 3},
20    3: {1, 2, 4},
21    4: {1, 3},
22}
23
24print(enumerate_triangles(graph))

Output:

text
[(1, 2, 3), (1, 3, 4)]

The ordering conditions v > u and w > v prevent duplicates.

Backtracking for More General Cases

When the target is more complex, backtracking is common. The core idea is to build a candidate subgraph one vertex at a time, while maintaining enough state to rule out dead branches early.

That is the same shape you see in classic clique enumeration algorithms such as Bron-Kerbosch. The power comes from pruning, not from blind recursion.

For connected subgraphs of fixed size k, one strategy is:

  1. choose a starting vertex
  2. maintain a frontier of expandable neighbors
  3. add a frontier vertex
  4. recurse until size k is reached

This avoids generating disconnected subsets and then filtering them later.

Choosing the Right Algorithm

Use a specialized method whenever possible:

  • triangles: intersection-based methods
  • maximal cliques: Bron-Kerbosch variants
  • pattern graphs: subgraph-isomorphism or motif algorithms
  • connected fixed-size subgraphs: frontier-based backtracking

A specialized algorithm is usually much faster than forcing everything through one general enumeration engine.

Common Pitfalls

The biggest mistake is not defining the target subgraph precisely. Without that, the algorithm and the output format are both ambiguous.

Another mistake is forgetting duplicate control. In graph enumeration, the same subgraph can often be discovered through multiple traversal orders unless you enforce a canonical ordering.

A third issue is using brute force on graphs that already require pruning. If the graph is nontrivial, generating all vertex subsets is usually a dead end.

Summary

  • Subgraph enumeration is a family of problems, not one single algorithm.
  • Always define the target pattern or property first.
  • Enumeration becomes practical only when you prune aggressively or specialize to the subgraph type.
  • Triangle and clique enumeration are common examples with dedicated algorithms.
  • Duplicate elimination through canonical ordering is essential for correct output.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.