首先,中介中心性是个啥?它是一个对于图中顶点重要程度的度量标准。那么它度量哪个方面的重要程度呢?
我们可以使用身边社交网络来做一个例子。这个有点像是我们身边那种社交达人,我们认识的不少朋友可能都是通过他/她认识的,这个人起到了中介的作用。那么这个人的中介中心性就是很高的。
严格意义上来表述,中介中心性指的是一个结点担任其它两个结点之间最短路的桥梁的次数。一个结点充当“中介”的次数越高,它的中介中心度就越大。如果要考虑标准化的问题,可以用一个结点承担最短路桥梁的次数除以所有的路径数量。这个就是什么是中介中心性,计算一个节点的介于中心性的方式就是对于这个图中的任意两个其他顶点,用这个结点承担这两个顶点间最短路桥梁的次数除以所有的路径数量,然后将这些所有的任意两个顶点组合计算出的值,求和,就是最后的结果。
怎么说呢,当时遇到这个问题第一感觉就是,说起来计算过程挺清晰的,但是对于如何实现完全手足无措。
这里首先要解决的问题是,我们虽然都熟练掌握Dijkstra算法和Floyd算法,可以计算任意两点的最短路径的长度,但是计算最短路径的条数并不会。。。
我们可以根据一个我们很容易发现的事实设计出一个可行的算法,当然这个算法的实现效率不够高,但是它足够易于理解。
首先是有这样一个关系。对于任意的两个顶点u,v,这两个顶点的一条最短路径经过了顶点a,b,c。。。那么从u到v的最短路径的条数,等于:u到a的最短路径的条数乘以a到v的最短路径的条数,u到b的最短路径的条数乘以b到v的最短路径的条数,u到b的最短路径的条数乘以b到v的最短路径的条数。。。以上这些所有值之和。
这个关系应该是很容易理解的,严格的数学证明不是我擅长的东西,我只能说显而易见它是对的。
那么接下来的实现就很简单了啊,很容易发现根据我们找到的这个基本的性质,我们只要求出几个原子的点对之间的最短路径的条数,那么就可以通过不断地合并求出任意的两个点对之间的最短路径的条数。这本质上是一个分治策略的实现,同时我们需要设计出好的用于存储每一步的计算结果的动态规划的数据结构。最终得到的代码如下:
/** * 用于计算一个图某顶点的betweennessCentrality. * @param g 待计算的图,它必须是一个非空的图. * @param v 待计算的图g中的顶点,它必须是图g中存在的一个顶点. * @return 一个正的浮点数,它表示待计算的图g中顶点v的betweennessCentrality. */ public static double betweennessCentrality(Graph<Vertex, Edge> g, Vertex v) { double num = 0; List<Vertex> myListV = new ArrayList<Vertex>(); for (Vertex mv : g.vertices()) { myListV.add(mv); } int n = myListV.size(); double[][] dm = new double[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { dm[i][j] = 1000; } } for (int i = 0; i < n; i++) { dm[i][i] = 0; } List<Edge> myListE = new ArrayList<Edge>(); for (Edge me : g.edges()) { if (!(me instanceof HyperEdge)) { myListE.add(me); } } for (Edge me : myListE) { int a = myListV.indexOf(me.getVertices().get(0)); int b = myListV.indexOf(me.getVertices().get(1)); if (me instanceof DirectedEdge) { dm[a][b] = 1; dm[b][a] = 1; } if (me instanceof UndirectedEdge) { dm[a][b] = 1; dm[b][a] = 1; } } int[][] nb = new int[n][n]; for (int i = 0; i < n; i++) { int[] notem = new int[n]; int[] numm = new int[n]; for (int ii = 0; ii < n; ii++) { notem[ii] = -1; numm[ii] = 0; } notem[i] = 0; numm[i] = 1; for (int j = 0; j < n - 1; j++) { for (int ii = 0; ii < n; ii++) { for (int jj = 0; jj < n; jj++) { if (notem[ii] == j && (notem[jj] == -1 || notem[jj] > j) && dm[ii][jj] == 1) { notem[jj] = j + 1; numm[jj] = numm[jj] + numm[ii]; } } } } for (int j = 0; j < n; j++) { nb[i][j] = numm[j]; } } int c = myListV.indexOf(v); for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { if (i != j && i != c && j != c) { num = num + nb[i][c] * nb[c][j] / nb[i][j]; } } } return num; }