You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中基于Floyd-Warshall算法的介数中心性计算错误排查

排查介数中心性计算错误的关键点

我帮你梳理了代码里的几个核心问题,这些应该就是导致结果不符合预期的原因:


1. 初始化阶段的错误:未处理自身节点的情况

在无向无权图中,一个节点到自身的最短距离应该是0,路径就是它自己。但你的代码里,当i == j时,因为adjMatrix[i][j] == 0,会被设置为distance[i][j] = noPath,R[i][j] = -5000,这完全不符合逻辑。而且后续统计时还会把这种无效路径算入计数,导致节点自身的计数虚高。

修正初始化代码:

for (int i = 0; i < numVertices; i++) {
    for (int j = 0; j < numVertices; j++) {
        if (i == j) {
            distances[i][j] = 0;
            R[i][j] = i; // 自身到自身的前驱是自己
        } else if (adjMatrix[i][j] == 0) {
            distances[i][j] = noPath;
            R[i][j] = -5000;
        } else {
            distances[i][j] = adjMatrix[i][j];
            R[i][j] = j;
        }
    }
}

2. Floyd-Warshall未处理多条最短路径的情况

你的代码只在发现更短路径时更新R数组,但当存在多条等长的最短路径时,当前逻辑只会记录其中一条,导致后续统计的路径数严重缺失——这是介数计算错误的核心原因,因为介数需要统计所有最短路径,而非单条。

要解决这个问题,你需要额外维护一个pathCount数组,记录每个i->j的最短路径总数,同时在发现等长路径时更新计数:

添加路径计数的Floyd-Warshall修正:

// 新增路径计数数组
int[][] pathCount = new int[numVertices][numVertices];
// 初始化计数
for (int i = 0; i < numVertices; i++) {
    for (int j = 0; j < numVertices; j++) {
        if (i == j) {
            pathCount[i][j] = 1;
        } else if (adjMatrix[i][j] != 0) {
            pathCount[i][j] = 1;
        } else {
            pathCount[i][j] = 0;
        }
    }
}

// 修改Floyd-Warshall循环
for (int k = 0; k < numVertices; k++) {
    for (int i = 0; i < numVertices; i++) {
        for (int j = 0; j < numVertices; j++) {
            if (distances[i][k] != noPath && distances[k][j] != noPath) {
                if (distances[i][j] > distances[i][k] + distances[k][j]) {
                    // 发现更短路径,更新距离、前驱和计数
                    distances[i][j] = distances[i][k] + distances[k][j];
                    R[i][j] = R[i][k];
                    pathCount[i][j] = pathCount[i][k] * pathCount[k][j];
                } else if (distances[i][j] == distances[i][k] + distances[k][j] && k != j) {
                    // 发现等长的最短路径,累加计数
                    pathCount[i][j] += pathCount[i][k] * pathCount[k][j];
                }
            }
        }
    }
}

3. 统计阶段包含了无效的i==j路径

介数中心性的定义是:统计所有不同节点对(s,t)(s≠t)的最短路径中,经过目标节点v的次数。你的代码遍历了所有i和j,包括i==j的情况,这会把每个节点自身的无效路径算入计数,导致结果偏差。

修正统计循环:

HashMap<Integer, Integer> frequencies = new HashMap<>();
for (int i = 0; i < numVertices; i++) {
    for (int j = 0; j < numVertices; j++) {
        if (i == j || distances[i][j] == noPath) {
            continue; // 跳过自身节点和不可达的情况
        }
        // 统计所有最短路径中经过的节点
        countNodesInAllShortestPaths(i, j, pathCount, distances, frequencies);
    }
}

4. 单路径枚举无法覆盖所有最短路径

你的findShortestPath方法只能找到一条最短路径,但介数需要统计所有最短路径中节点的出现次数。你需要实现一个递归方法来遍历所有可能的最短路径,结合pathCount数组来统计次数:

新增统计所有路径节点的方法:

private void countNodesInAllShortestPaths(int s, int t, int[][] pathCount, int[][] distances, HashMap<Integer, Integer> frequencies) {
    if (s == t) return;
    // 累加当前节点的出现次数:s到t的所有路径都会经过s,所以加pathCount[s][t]次
    frequencies.put(s, frequencies.getOrDefault(s, 0) + pathCount[s][t]);
    // 遍历所有可能的中间节点k
    for (int k = 0; k < numVertices; k++) {
        if (k == s || distances[s][k] + distances[k][t] != distances[s][t]) {
            continue;
        }
        // 递归统计k到t的路径中的节点
        countNodesInAllShortestPaths(k, t, pathCount, distances, frequencies);
    }
}

最后:修正输出逻辑

你的输出代码里,先把索引映射到实际节点值,但最后打印的还是frequencies的key(索引),而不是temp里的实际节点值,这也会导致你看到的节点ID不对:

修正输出:

// 替换原来的输出逻辑
System.out.println("Top 5 nodes: \nNode - Count");
temp.entrySet().stream()
    .sorted(Map.Entry.comparingByValue(Collections.reverseOrder()))
    .limit(5)
    .forEach((node, frequency) -> System.out.println(node + " - " + frequency));

通过以上修正,应该就能得到正确的介数中心性结果,让节点50393960回到第一的位置。

内容的提问来源于stack exchange,提问作者user2764359

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:06:38