如何将GraphStream中AStar求得的Path转为Graph或移除非路径节点?
嘿,我刚好之前在GraphStream里处理过类似的需求,咱们一步步来解决这个问题:
首先得明确:GraphStream的Node和Edge对象是和所属的原始图绑定的,不能直接把一个图的节点/边对象添加到另一个图,这就是你之前尝试graph.addNode(n)失败的原因。不过有两种高效的方案,对应你两种不同的需求:
方案1:修改原图,移除非路径节点/边(高效,无需复制属性)
如果你只想保留原始图中最短路径的部分,这个方法最省事儿,不用重新创建任何节点/边,直接移除不需要的元素即可:
步骤:
- 先获取路径中所有节点的ID集合,用来判断哪些节点需要保留:
Set<String> pathNodeIds = p.getNodeSet().stream() .map(Node::getId) .collect(Collectors.toSet()); - 收集并移除所有不在路径中的节点(注意不能直接遍历原图节点时移除,会触发并发修改异常):
List<Node> nodesToRemove = new ArrayList<>(); for (Node node : graph) { if (!pathNodeIds.contains(node.getId())) { nodesToRemove.add(node); } } nodesToRemove.forEach(graph::removeNode);提示:移除节点时,GraphStream会自动删除该节点关联的所有边,所以这一步后,原图剩下的边都是路径节点之间的边。
- (可选)如果需要精准保留路径上的边(而非路径节点之间的所有边),可以再移除多余的边:
Set<Edge> pathEdges = p.getEdgeSet(); List<Edge> edgesToRemove = new ArrayList<>(); for (Edge edge : graph.getEdgeSet()) { if (!pathEdges.contains(edge)) { edgesToRemove.add(edge); } } edgesToRemove.forEach(graph::removeEdge);
方案2:创建全新的路径图(独立于原图,适合需要保留原图的场景)
如果你需要一个完全独立的只包含最短路径的新图,就需要复制路径上的节点/边及其属性。虽然需要手动复制属性,但可以写个工具方法简化操作:
步骤:
- 先创建一个新的空图:
Graph pathGraph = new SingleGraph("ShortestPathGraph"); - 写一个通用的属性复制工具方法(避免重复代码):
private static void copyElementAttributes(Element source, Element target) { for (String attrKey : source.getAttributeKeySet()) { target.setAttribute(attrKey, source.getAttribute(attrKey)); } } - 复制路径上的节点及其所有属性:
for (Node originalNode : p.getNodeSet()) { Node newNode = pathGraph.addNode(originalNode.getId()); copyElementAttributes(originalNode, newNode); } - 复制路径上的边及其所有属性(注意保留边的方向):
for (Edge originalEdge : p.getEdgeSet()) { Edge newEdge = pathGraph.addEdge( originalEdge.getId(), originalEdge.getSourceNode().getId(), originalEdge.getTargetNode().getId(), originalEdge.isDirected() ); copyElementAttributes(originalEdge, newEdge); }
为什么没有更“一键式”的方法?
目前GraphStream并没有内置的Path转Graph的API,因为路径本质上只是节点和边的集合,而每个图的底层实现可能不同(比如SingleGraph vs MultiGraph)。不过上面两种方案已经是最高效的实现了:
- 方案1的时间复杂度是O(N+E),只需要遍历一次原图的节点和边;
- 方案2的时间复杂度是O(Pn+Pe),其中Pn是路径节点数,Pe是路径边数,比遍历整个原图要快得多。
内容的提问来源于stack exchange,提问作者simonalexander2005




