@@ -101,6 +101,11 @@ public EdgeBetweennessAnalyzer(Graph<String, Edge> graph) {
101101
102102 /**
103103 * Compute edge betweenness centrality using Brandes' algorithm (BFS variant).
104+ *
105+ * <p>Uses lazy initialization: only vertices reachable from each BFS source
106+ * are initialized, avoiding the O(V) per-source setup cost that made total
107+ * initialization O(V²). For sparse or disconnected graphs this is a major
108+ * win since each BFS touches only its connected component.</p>
104109 */
105110 public void compute () {
106111 betweenness .clear ();
@@ -111,54 +116,56 @@ public void compute() {
111116 Collection <String > vertices = graph .getVertices ();
112117
113118 for (String s : vertices ) {
114- // BFS from s
115- Stack <String > stack = new Stack <>();
119+ // BFS from s — lazy init: only reachable vertices are tracked.
120+ // predecessors/dist/sigma use containsKey checks instead of
121+ // pre-populating entries for every vertex in the graph.
122+ ArrayDeque <String > stack = new ArrayDeque <>();
116123 Map <String , List <String >> predecessors = new HashMap <>();
117124 Map <String , Integer > dist = new HashMap <>();
118125 Map <String , Double > sigma = new HashMap <>();
119126
120- for (String v : vertices ) {
121- predecessors .put (v , new ArrayList <>());
122- dist .put (v , -1 );
123- sigma .put (v , 0.0 );
124- }
125127 dist .put (s , 0 );
126128 sigma .put (s , 1.0 );
129+ predecessors .put (s , new ArrayList <>());
127130
128131 Queue <String > queue = new ArrayDeque <>();
129132 queue .add (s );
130133
131134 while (!queue .isEmpty ()) {
132135 String v = queue .poll ();
133136 stack .push (v );
137+ int distV = dist .get (v );
138+ double sigmaV = sigma .get (v );
134139 for (String w : graph .getNeighbors (v )) {
135- // First visit?
136- if (dist .get (w ) < 0 ) {
137- dist .put (w , dist .get (v ) + 1 );
140+ // First visit? (not yet in dist map)
141+ if (!dist .containsKey (w )) {
142+ dist .put (w , distV + 1 );
143+ sigma .put (w , 0.0 );
144+ predecessors .put (w , new ArrayList <>());
138145 queue .add (w );
139146 }
140147 // Shortest path via v?
141- if (dist .get (w ) == dist . get ( v ) + 1 ) {
142- sigma .put (w , sigma .get (w ) + sigma . get ( v ) );
148+ if (dist .get (w ) == distV + 1 ) {
149+ sigma .put (w , sigma .get (w ) + sigmaV );
143150 predecessors .get (w ).add (v );
144151 }
145152 }
146153 }
147154
148- // Back-propagation
149- Map <String , Double > delta = new HashMap <>();
150- for (String v : vertices ) delta .put (v , 0.0 );
155+ // Back-propagation — only over vertices in the stack (reachable from s)
156+ Map <String , Double > delta = new HashMap <>(stack .size () * 2 );
151157
152158 while (!stack .isEmpty ()) {
153159 String w = stack .pop ();
160+ double deltaW = delta .getOrDefault (w , 0.0 );
154161 for (String v : predecessors .get (w )) {
155- double c = (sigma .get (v ) / sigma .get (w )) * (1.0 + delta . get ( w ) );
162+ double c = (sigma .get (v ) / sigma .get (w )) * (1.0 + deltaW );
156163 // Find the edge between v and w
157164 Edge edge = findEdge (v , w );
158165 if (edge != null ) {
159166 betweenness .put (edge , betweenness .getOrDefault (edge , 0.0 ) + c );
160167 }
161- delta .put (v , delta . get ( v ) + c );
168+ delta .merge (v , c , Double :: sum );
162169 }
163170 }
164171 }
0 commit comments