Class: | Centrality Network theory |
Data: | Connected graph |
Time: | O( |
Space: | O( |
In network theory, Brandes' algorithm is an algorithm for calculating the betweenness centrality of vertices in a graph. The algorithm was first published in 2001 by Ulrik Brandes.[1] Betweenness centrality, along with other measures of centrality, is an important measure in many real-world networks, such as social networks and computer networks.[2] [3] [4]
There are several metrics for the centrality of a node, one such metric being the betweenness centrality.[5] For a node
v
whereCB(v)=\sums\sumt
\sigmast(v) \sigmast
\sigmast
s
t
\sigmast(v)
v
By convention,
\sigmast=1
s=t
\sigmast(v)=0
v
s
t
The quantity
is known as the pair dependency of\deltast(v)=
\sigmast(v) \sigmast
st
v
s
t
v
v
s
with which, we can obtain the concise formulation,\deltas(v)=\sumt\deltast(v)
.CB(v)=\sums\deltas(v)
Brandes' algorithm calculates the betweenness centrality of all nodes in a graph. For every vertex
s
The number of shortest paths
\sigmasv
s
v
s
d(v)
s
v
p(v)
This lends itself to a simple iterative formula for.p(v)=\{u\inV\mid(u,v)\inE ∧ d(u)+1=d(v)\}
\sigmasv
which essentially states that, if,\sigmasv=\sumu\sigmasu
v
d(v)
d(v)-1
v
v
Brandes proved the following recursive formula for vertex dependencies:
where the sum is taken over all vertices,\deltas(u)=\sumv
\sigmasu \sigmasv ⋅ (1+\deltas(v))
v
s
u
s
u
d(u)
d(u)+1
It turns out that the dependencies of
s
u
O(|E|)
s
For each popped node
v
u\inp(v)
v
\deltas(u)
Crucially, every layer propagates its dependencies completely, before moving to the layer with lower depth, due to the nature of breadth-first search. Once the propagation reaches back to.
\sigmasu \sigmasv ⋅ (1+\deltas(v))
s
v
\deltas(v)
CB(v)
After.CB(v)=\sums\deltas(v)
|V|
CB(v)
v
The following pseudocode illustrates Brandes' algorithm on an unweighted directed graph.[8] algorithm Brandes(Graph) is for each u in Graph.Vertices do CB[''u''] ← 0 for each s in Graph.Vertices do for each v in Graph.Vertices do δ[''v''] ← 0 // Single dependency of s on v prev[''v''] ← empty list // Immediate predecessors of v during BFS σ[''v''] ← 0 // Number of shortest paths from s to v (s implied) dist[''v''] ← null // No paths are known initially, σ[''s''] ← 1 // except the start vertex dist[''s''] ← 0 Q ← queue containing only s // Breadth-first search S ← empty stack // Record the order in which vertices are visited // Single-source shortest paths while Q is not empty do u ← Q.dequeue S.push(u) for each v in Graph.Neighbours[''u''] do if dist[''v''] = null then dist[''v''] ← dist[''u''] + 1 Q.enqueue(v) if dist[''v''] = dist[''u''] + 1 then σ[''v''] ← σ[''v''] + σ[''u''] prev[''v''].append(u) // Backpropagation of dependencies while S is not empty do v ← S.pop for each u in prev[''v''] do δ[''u''] ← δ[''u''] + σ[''u''] / σ[''v''] * (1 + δ[''v'']) if u ≠ s then CB[''v''] ← CB[''v''] + δ[''v''] // Halved for undirected graphs return CB
The running time of the algorithm is expressed in terms of the number of vertices
|V|
|E|
For each vertex
s
O(|V|+|E|)
|E|
|V|
|V|-1
In the backpropagation stage, every vertex is popped off the stack, and its predecessors are iterated over. However, since each predecessor entry corresponds to an edge in the graph, this stage is also bounded by
O(|E|)
The overall running time of the algorithm is therefore
O(|V||E|)
O(|V|3)
O(|V|2)
|E|
O(|V|+|E|)
The algorithm can be generalised to weighted graphs by using Dijkstra's algorithm instead of breadth-first search. When operating on undirected graphs, the betweenness centrality may be divided by 2, to avoid double counting each path's reversed counterpart. Variants also exist to calculate different measures of centrality, including betweenness with paths at most length
k