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

Commit 467366c

Browse files
perf: O(1) edge lookup via pre-built index in EdgeBetweennessAnalyzer
Brandes' algorithm back-propagation calls findEdge(v, w) inside the inner loop — O(V×E) total calls, each O(degree) in JUNG's findEdge. Build a bidirectional HashMap<String, HashMap<String, Edge>> at construction time. findEdge() now does two HashMap.get() calls (O(1) amortized) instead of graph.findEdge() which scans incident edges linearly. For dense graphs this reduces back-propagation from O(V × E × avg_degree) to O(V × E).
1 parent 4328537 commit 467366c

1 file changed

Lines changed: 39 additions & 3 deletions

File tree

Gvisual/src/gvisual/EdgeBetweennessAnalyzer.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646
public class EdgeBetweennessAnalyzer {
4747

4848
private final Graph<String, Edge> graph;
49+
/**
50+
* O(1) edge lookup: edgeIndex.get(u).get(v) returns the Edge between u and v.
51+
* Built once at construction, replacing O(degree) graph.findEdge() calls
52+
* in the back-propagation inner loop of Brandes' algorithm.
53+
*/
54+
private final Map<String, Map<String, Edge>> edgeIndex;
4955
private Map<Edge, Double> betweenness;
5056
private List<EdgeScore> ranking;
5157
private Set<Edge> bridges;
@@ -91,12 +97,34 @@ public String toString() {
9197
public EdgeBetweennessAnalyzer(Graph<String, Edge> graph) {
9298
if (graph == null) throw new IllegalArgumentException("Graph must not be null");
9399
this.graph = graph;
100+
this.edgeIndex = buildEdgeIndex();
94101
this.betweenness = new LinkedHashMap<>();
95102
this.ranking = new ArrayList<>();
96103
this.bridges = new HashSet<>();
97104
this.computed = false;
98105
}
99106

107+
/**
108+
* Builds a bidirectional edge index: for every edge (u,v), stores
109+
* edgeIndex[u][v] = edge and edgeIndex[v][u] = edge (for undirected).
110+
* This turns O(degree) findEdge lookups into O(1) HashMap gets.
111+
*/
112+
private Map<String, Map<String, Edge>> buildEdgeIndex() {
113+
boolean directed = isDirected();
114+
Map<String, Map<String, Edge>> idx = new HashMap<>();
115+
for (Edge e : graph.getEdges()) {
116+
edu.uci.ics.jung.graph.util.Pair<String> ep = graph.getEndpoints(e);
117+
if (ep == null) continue;
118+
String u = ep.getFirst();
119+
String v = ep.getSecond();
120+
idx.computeIfAbsent(u, k -> new HashMap<>()).put(v, e);
121+
if (!directed) {
122+
idx.computeIfAbsent(v, k -> new HashMap<>()).put(u, e);
123+
}
124+
}
125+
return idx;
126+
}
127+
100128
public void setTitle(String title) { this.title = title; }
101129

102130
/**
@@ -192,10 +220,18 @@ public void compute() {
192220
computed = true;
193221
}
194222

223+
/**
224+
* O(1) edge lookup via pre-built index, replacing O(degree) graph.findEdge().
225+
*/
195226
private Edge findEdge(String v, String w) {
196-
Edge e = graph.findEdge(v, w);
197-
if (e == null) e = graph.findEdge(w, v);
198-
return e;
227+
Map<String, Edge> adj = edgeIndex.get(v);
228+
if (adj != null) {
229+
Edge e = adj.get(w);
230+
if (e != null) return e;
231+
}
232+
// Fallback for directed graphs: check reverse direction
233+
Map<String, Edge> revAdj = edgeIndex.get(w);
234+
return revAdj != null ? revAdj.get(v) : null;
199235
}
200236

201237
private boolean isDirected() {

0 commit comments

Comments
 (0)