Skip to content
This repository was archived by the owner on Jun 18, 2026. It is now read-only.

Commit 7d2425c

Browse files
refactor(TopologicalSortAnalyzer): cache directed adjacency map and analysis result
TopologicalSortAnalyzer rebuilt the directed adjacency map (O(V+E)) in every public method call — analyze(), analyzeDependencies(), countChoicePoints(). generateSummary() was worst: it called analyze() + countChoicePoints(), which itself called analyze() again, resulting in 3× redundant O(V+E) traversals and 3× redundant adjacency map constructions per summary generation. Cache both buildDirectedAdj() and analyze() results as lazy instance fields. Subsequent calls to any method reuse the cached structures instead of recomputing from scratch. Impact: generateSummary() drops from ~3× O(V+E) graph traversals to 1×. analyzeDependencies() no longer rebuilds adjacency + re-runs full Kahn's algorithm just to get the depth map.
1 parent dd5dbfc commit 7d2425c

1 file changed

Lines changed: 15 additions & 2 deletions

File tree

Gvisual/src/gvisual/TopologicalSortAnalyzer.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ public class TopologicalSortAnalyzer {
3333

3434
private final Graph<String, Edge> graph;
3535

36+
/** Lazily-computed directed adjacency — avoids rebuilding O(V+E) per method call. */
37+
private GraphUtils.DirectedAdj cachedAdj;
38+
39+
/** Lazily-computed full analysis result — reused by generateSummary, countChoicePoints, analyzeDependencies. */
40+
private TopologicalSortResult cachedResult;
41+
3642
/**
3743
* Create a new analyzer for the given graph.
3844
*
@@ -188,7 +194,10 @@ public VertexDependencyInfo(String vertex, Set<String> allDependencies,
188194
* adjacency builder extracted from this class.
189195
*/
190196
private GraphUtils.DirectedAdj buildDirectedAdj() {
191-
return GraphUtils.buildDirectedAdjacencyMap(graph);
197+
if (cachedAdj == null) {
198+
cachedAdj = GraphUtils.buildDirectedAdjacencyMap(graph);
199+
}
200+
return cachedAdj;
192201
}
193202

194203
// ── Core algorithms ─────────────────────────────────────────
@@ -206,6 +215,9 @@ private GraphUtils.DirectedAdj buildDirectedAdj() {
206215
* @return complete topological sort analysis
207216
*/
208217
public TopologicalSortResult analyze() {
218+
if (cachedResult != null) {
219+
return cachedResult;
220+
}
209221
GraphUtils.DirectedAdj adj = buildDirectedAdj();
210222
Map<String, Set<String>> successors = adj.successors;
211223
Map<String, Set<String>> predecessors = adj.predecessors;
@@ -301,9 +313,10 @@ public TopologicalSortResult analyze() {
301313
criticalPath = reconstructCriticalPath(depthMap, predecessors, longestPathLength);
302314
}
303315

304-
return new TopologicalSortResult(isDAG, sortedOrder, cycles, depthMap,
316+
cachedResult = new TopologicalSortResult(isDAG, sortedOrder, cycles, depthMap,
305317
dependencyCount, dependentCount, roots, leaves,
306318
longestPathLength, criticalPath);
319+
return cachedResult;
307320
}
308321

309322
/**

0 commit comments

Comments
 (0)