JGraphT 实现指定长度的入度路径枚举:从目标节点反向遍历所有 k-边路径

冬婷酱_8949

冬婷酱_8949

2026-07-25

447人浏览

原创

JGraphT 实现指定长度的入度路径枚举:从目标节点反向遍历所有 k-边路径

本文介绍如何在 jgrapht 中高效获取所有终止于指定顶点、且恰好包含 k 条边的有向路径,涵盖内置算法适配、方向处理技巧及完整自定义动态规划实现。

本文介绍如何在 jgrapht 中高效获取所有终止于指定顶点、且恰好包含 k 条边的有向路径,涵盖内置算法适配、方向处理技巧及完整自定义动态规划实现。

在使用 JGraphT 处理有向图分析时,一个常见但未被直接支持的需求是:枚举所有以某顶点 v 为终点、且长度(边数)恰好为 k 的路径。例如,在图 A→B→C, D→E→C, F→C 中,调用 pathsTo(C, 2) 应返回 [A,B,C] 和 [D,E,C] —— 注意这是 入路径(in-paths),而非从 C 出发的路径。

JGraphT 不提供开箱即用的 allPathsTo(vertex, length) 方法,但可通过以下三种策略实现,需根据场景权衡简洁性与完备性:

✅ 推荐方案:反向图 + BFS 或 Dijkstra(适用于单路径/近似场景)

由于 JGraphT 的最短路径算法(如 DijkstraShortestPath)默认计算从源到目标的路径,要获取“进入 C”的路径,最自然的方式是将图逻辑反转——即构造反向图(C 变为起点),再运行受限深度的遍历:

import org.jgrapht.Graph;
import org.jgrapht.Graphs;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.alg.shortestpath.SingleSourcePaths;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;

// 原始有向图
Graph<integer defaultedge> original = new DefaultDirectedGraph(DefaultEdge.class);
original.addVertex(1); original.addVertex(2); original.addVertex(3); // A=1, B=2, C=3
original.addEdge(1, 2); // A→B
original.addEdge(2, 3); // B→C
original.addEdge(4, 5); // D→E
original.addEdge(5, 3); // E→C
original.addEdge(6, 3); // F→C

// 构造反向图(关键步骤)
Graph<integer defaultedge> reversed = Graphs.asUndirected(original); // ❌ 错误!仅当图本就无向才安全
// ✅ 正确做法:显式构建反向有向图
Graph<integer defaultedge> reverseGraph = new DefaultDirectedGraph(DefaultEdge.class);
original.vertexSet().forEach(reverseGraph::addVertex);
original.edgeSet().forEach(e -> reverseGraph.addEdge(
    original.getEdgeTarget(e),  // 原终点 → 新起点
    original.getEdgeSource(e)   // 原起点 → 新终点
));

// 从目标顶点 C 开始,找最多 k 条边的路径(Dijkstra 支持权重截断,此处设 unit weight)
DijkstraShortestPath<integer defaultedge> dsp = 
    new DijkstraShortestPath(reverseGraph, (double) k);
SingleSourcePaths<integer defaultedge> pathsFromC = dsp.getPaths(3); // C=3

// 提取所有距离恰好为 k 的路径(注意:仅返回一条最短路径,非全部)
pathsFromC.getVertexSet().stream()
    .filter(v -> pathsFromC.getDistance(v) == k)
    .map(pathsFromC::getPath)
    .forEach(path -> System.out.println("One path to C of length " + k + ": " + path));</integer></integer></integer></integer></integer>

⚠️ 注意:此方法每顶点仅返回一条路径(最短/最早发现路径),无法覆盖多路径情况(如 A→B→C 和 A→D→C 并存时只返回其一)。若业务允许单解或图中无重路径,该方案简洁高效;否则需转向下述完整方案。

Oiiyao
Oiiyao

Oiiyao是一款AI文本写作工具,AI视频本地化平台。

下载

⚙️ 完整方案:动态规划枚举所有 k-边入路径(推荐用于精确需求)

为确保获取 所有 长度为 k 的入路径,需手动实现基于状态 (vertex, length) 的记忆化搜索。核心思想是:

pathsTo(v, k) = 所有 u 满足 u → v ∈ E 的 pathsTo(u, k−1) 后缀拼接 v

以下是可直接运行的通用实现:

import java.util.*;

public class AllPathEnumerator {
    private final Graph<integer defaultedge> graph;

    public AllPathEnumerator(Graph<integer defaultedge> graph) {
        this.graph = graph;
    }

    /**
     * 返回所有以 target 终止、且恰好含 k 条边的路径(每个路径为顶点列表,从起点到 target)
     */
    public List<list>> allPathsTo(Integer target, int k) {
        if (k >>> memo = new HashMap();

        return dfs(target, k, memo);
    }

    private List<list>> dfs(Integer v, int len, 
                                  Map<integer map list>>>> memo) {
        if (len == 0) {
            return Collections.singletonList(Collections.singletonList(v));
        }
        if (len == 1) {
            List<list>> result = new ArrayList();
            for (Integer u : Graphs.predecessorListOf(graph, v)) {
                result.add(Arrays.asList(u, v));
            }
            return result;
        }

        memo.computeIfAbsent(v, k -> new HashMap());
        if (memo.get(v).containsKey(len)) {
            return memo.get(v).get(len);
        }

        List<list>> result = new ArrayList();
        for (Integer u : Graphs.predecessorListOf(graph, v)) {
            List<list>> prevPaths = dfs(u, len - 1, memo);
            for (List<integer> path : prevPaths) {
                List<integer> extended = new ArrayList(path);
                extended.add(v);
                result.add(extended);
            }
        }

        memo.get(v).put(len, result);
        return result;
    }
}

// 使用示例
AllPathEnumerator enumerator = new AllPathEnumerator(original);
List<list>> paths = enumerator.allPathsTo(3, 2); // C=3, k=2
paths.forEach(System.out::println); // 输出: [1, 2, 3], [4, 5, 3]</list></integer></integer></list></list></list></integer></list></list></integer></integer>

优势:精确、完备、支持任意 k、自动去重(路径本身不同即视为不同)、时间复杂度可控(O(|E| × k × avg_path_count))。
? 优化提示:对大规模图,可增加 maxResults 限制或改用迭代 DP 表避免递归栈溢出。

? 总结与选型建议

  • 若只需一条代表路径且图稀疏 → 使用 反向图 + DijkstraShortestPath 或 BreadthFirstIterator(设置 maxDepth = k);
  • 若需全部路径且 k 较小(≤ 10)→ 采用上述 DFS+记忆化动态规划,代码清晰、易于调试;
  • 避免 Floyd-Warshall:其时间复杂度 O(|V|³) 过高,且仍需额外回溯生成路径,得不偿失;
  • 始终验证图方向:JGraphT 的 predecessorListOf(graph, v) 是获取入边邻居的正确方式,无需手动反转图结构。

通过合理选择策略,你能在 JGraphT 生态中稳健实现“指定长度入路径枚举”这一关键图分析能力。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

8897

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

6122

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

5492

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

984

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

808

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1156

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2349

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

19691

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1075

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.1万人学习