
本文旨在帮助开发者理解和实现双向路径搜索算法。通过分析常见的实现错误,并提供改进方案,本文将详细介绍如何使用Java构建高效的双向搜索树,并从搜索树中正确提取完整的路径信息,最终实现从起点到终点的完整路径搜索。
双向路径搜索是一种在图中寻找从起点到终点路径的优化算法。它同时从起点和终点开始搜索,当两个搜索方向相遇时,就找到了连接起点和终点的路径。相比于单向搜索,双向搜索通常能够更快地找到目标路径,尤其是在搜索空间较大的情况下。
原始代码中存在一些关键问题,导致无法正确构建和使用双向搜索树:
为了解决上述问题,我们需要进行以下改进:
立即学习“Java免费学习笔记(深入)”;
以下是改进后的 Java 代码示例:
import java.util.*;
public class BidirectionalSearch {
private final Graph graph;
private final Map<Vertex, Vertex> searchTreeParentByChildFromStart = new HashMap<>();
private final Map<Vertex, Vertex> searchTreeParentByChildFromEnd = new HashMap<>();
public BidirectionalSearch(Graph graph) {
this.graph = graph;
}
public BidirectionalSearch buildSearchTree(Vertex start, Vertex end) {
if (!graph.vertices().containsAll(List.of(start, end)))
throw new IllegalArgumentException("start or stop vertices not from this graph");
if (start.equals(end))
return this;
searchTreeParentByChildFromStart.clear();
searchTreeParentByChildFromEnd.clear();
Queue<Vertex> unvisitedVertexQueueFromStart = new ArrayDeque<>();
Queue<Vertex> unvisitedVertexQueueFromEnd = new ArrayDeque<>();
unvisitedVertexQueueFromStart.add(start);
unvisitedVertexQueueFromEnd.add(end);
searchTreeParentByChildFromStart.put(start, null);
searchTreeParentByChildFromEnd.put(end, null);
Vertex intersectionVertex = null;
while (!unvisitedVertexQueueFromStart.isEmpty() && !unvisitedVertexQueueFromEnd.isEmpty()) {
Vertex curStart = unvisitedVertexQueueFromStart.poll();
for (Edge e : curStart.edges()) {
Vertex neighbor = e.to();
if (!searchTreeParentByChildFromStart.containsKey(neighbor)) {
searchTreeParentByChildFromStart.put(neighbor, curStart);
unvisitedVertexQueueFromStart.add(neighbor);
if (searchTreeParentByChildFromEnd.containsKey(neighbor)) {
intersectionVertex = neighbor;
break; // Found intersection
}
}
}
if (intersectionVertex != null) break;
Vertex curEnd = unvisitedVertexQueueFromEnd.poll();
for (Edge e : curEnd.edges()) {
Vertex neighbor = e.to();
if (!searchTreeParentByChildFromEnd.containsKey(neighbor)) {
searchTreeParentByChildFromEnd.put(neighbor, curEnd);
unvisitedVertexQueueFromEnd.add(neighbor);
if (searchTreeParentByChildFromStart.containsKey(neighbor)) {
intersectionVertex = neighbor;
break; // Found intersection
}
}
}
if (intersectionVertex != null) break;
}
return this;
}
public List<Vertex> getPath(Vertex start, Vertex end) {
buildSearchTree(start, end);
Vertex intersection = findIntersection(start, end);
if (intersection == null) {
return Collections.emptyList(); // No path found
}
List<Vertex> pathToIntersectionFromStart = buildPath(searchTreeParentByChildFromStart, intersection);
List<Vertex> pathToIntersectionFromEnd = buildPath(searchTreeParentByChildFromEnd, intersection);
Collections.reverse(pathToIntersectionFromEnd); // Reverse the end path
List<Vertex> fullPath = new ArrayList<>();
fullPath.addAll(pathToIntersectionFromStart);
fullPath.addAll(pathToIntersectionFromEnd.subList(1, pathToIntersectionFromEnd.size())); // Avoid duplicate intersection vertex
return fullPath;
}
private Vertex findIntersection(Vertex start, Vertex end) {
for (Vertex vertex : searchTreeParentByChildFromStart.keySet()) {
if (searchTreeParentByChildFromEnd.containsKey(vertex)) {
return vertex;
}
}
return null;
}
private List<Vertex> buildPath(Map<Vertex, Vertex> searchTree, Vertex intersection) {
List<Vertex> path = new LinkedList<>();
Vertex current = intersection;
while (current != null) {
path.add(0, current); // Add to the beginning to reverse the path
current = searchTree.get(current);
}
return path;
}
// Example Graph, Vertex and Edge classes (replace with your actual implementations)
static class Graph {
private final Set<Vertex> vertices = new HashSet<>();
public void addVertex(Vertex vertex) {
vertices.add(vertex);
}
public Set<Vertex> vertices() {
return vertices;
}
}
static class Vertex {
private final String name;
private final List<Edge> edges = new ArrayList<>();
public Vertex(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void addEdge(Edge edge) {
edges.add(edge);
}
public List<Edge> edges() {
return edges;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Vertex vertex = (Vertex) o;
return Objects.equals(name, vertex.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
static class Edge {
private final Vertex from;
private final Vertex to;
private final int weight;
public Edge(Vertex from, Vertex to, int weight) {
this.from = from;
this.to = to;
this.weight = weight;
}
public Vertex to() {
return to;
}
}
public static void main(String[] args) {
// Example Usage
Graph graph = new Graph();
Vertex start = new Vertex("A");
Vertex b = new Vertex("B");
Vertex c = new Vertex("C");
Vertex end = new Vertex("D");
graph.addVertex(start);
graph.addVertex(b);
graph.addVertex(c);
graph.addVertex(end);
start.addEdge(new Edge(start, b, 1));
b.addEdge(new Edge(b, c, 1));
c.addEdge(new Edge(c, end, 1));
end.addEdge(new Edge(end, c, 1));
BidirectionalSearch search = new BidirectionalSearch(graph);
List<Vertex> path = search.getPath(start, end);
if (!path.isEmpty()) {
System.out.println("Path found: ");
for (Vertex vertex : path) {
System.out.print(vertex.getName() + " ");
}
System.out.println();
} else {
System.out.println("No path found.");
}
}
}代码解释:
双向路径搜索是一种强大的图搜索算法,可以有效地找到起点和终点之间的路径。 通过使用两个独立的搜索树,并正确地构建和合并路径,可以避免常见的实现错误,获得正确的搜索结果。 在实际应用中,需要根据图的结构和性能需求,对算法进行适当的优化。
以上就是双向路径搜索算法的Java实现及路径构建详解的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号