The betweenness centrality for each vertex is the number of these shortest paths that pass through the vertex.

  • perform BFS (or SSSP if weighted graphs) for each vertex
  • keep a stack of path for backtracking, i.e., traversing the graph in reverse BFS order
#include <iostream>
#include <queue>
#include <stack>
#include <vector>

auto brandes(const std::vector<int>& rowPtr, const std::vector<int>& colIdx)
{
  const auto         numVertices = rowPtr.size() - 1;
  std::vector<float> betweenness(numVertices, 0.0f);
  //For each vertex s, perform a BFS to establish levels and predecessors
  //! The time complexity is O(V^3)
  for(int i = 0; i < numVertices; i++)
  {
    std::vector<int> distance(numVertices, -1);    // Initialize distance from s
    std::vector<int> pathCount(numVertices, 0);    // Initialize path count
    std::vector<int> DepScore(numVertices, 0);     // Dependency score for each vertex
    std::queue<int>  pathQueue;                    // for BFS
    std::stack<int>  pathStack;

    std::vector<std::vector<int>> predecessor(numVertices);

    distance[i]  = 0;
    pathCount[i] = 1;
    pathQueue.push(i);
    // BFS traversal
    // for a single source vertex, the time complexity is O(V+E),
    //! so the overall time complexity is O(V+E) for each vertex i
    while(!pathQueue.empty())
    {
      const auto source = pathQueue.front();
      pathQueue.pop();
      pathStack.push(source);
      for(auto i = rowPtr[source]; i < rowPtr[source + 1]; i++)
      {
        const auto target = colIdx[i];
        if(distance[target] < 0)
        {
          pathQueue.push(target);
          distance[target] = distance[source] + 1;
        }
        // shortest path to target via source?
        if(distance[target] == distance[source] + 1)
        {
          pathCount[target] += pathCount[source];
          predecessor[target].push_back(source);
        }
      }
    }
    // traverse the graph in reverse BFS order
    // backtrack to propagate the dependency scores (delta) back through the graph,
    // to calculate the BC value for each node.
    //! The time complexity is O(V*V) for each vertex i
    //! There are V vertices in the stack, each of which has at most V-1 predecessors
    while(!pathStack.empty())
    {
      const auto curr = pathStack.top();
      pathStack.pop();

      for(auto prev : predecessor[curr])
      {
        DepScore[prev] +=
            (static_cast<float>(pathCount[prev]) / pathCount[curr]) * (1 + DepScore[curr]);
      }
      if(curr != i)
      {
        betweenness[curr] += DepScore[curr];
      }
    }
  }
  return betweenness;
}

int main()
{
  std::vector<int> rowPtr = { 0, 2, 4, 6, 8, 10, 12 };
  std::vector<int> colIdx = { 1, 2, 0, 3, 0, 1, 4, 1, 2, 5, 3, 5 };
  // Compute betweenness centrality using Brandes's algorithm
  // unweighted graph for simplicity
  auto betweenness = brandes(rowPtr, colIdx);
  // Print betweenness centrality
  std::cout << "Betweenness centrality:" << std::endl;
  for(int i = 0; i < betweenness.size(); i++)
  {
    std::cout << "Vertex " << i << ": " << betweenness[i] << std::endl;
  }
}