und*_*dog 6 java algorithm breadth-first-search data-structures
我正在上面的图表上运行广度优先搜索,以找到从中Node 0到达的最短路径Node 6.
我的代码
public List<Integer> shortestPathBFS(int startNode, int nodeToBeFound){
boolean shortestPathFound = false;
Queue<Integer> queue = new LinkedList<Integer>();
Set<Integer> visitedNodes = new HashSet<Integer>();
List<Integer> shortestPath = new ArrayList<Integer>();
queue.add(startNode);
shortestPath.add(startNode);
while (!queue.isEmpty()) {
int nextNode = queue.peek();
shortestPathFound = (nextNode == nodeToBeFound) ? true : false;
if(shortestPathFound)break;
visitedNodes.add(nextNode);
System.out.println(queue);
Integer unvisitedNode = this.getUnvisitedNode(nextNode, visitedNodes);
if (unvisitedNode != null) {
queue.add(unvisitedNode);
visitedNodes.add(unvisitedNode);
shortestPath.add(nextNode); //Adding the previous node of the visited node
shortestPathFound = (unvisitedNode == nodeToBeFound) ? true : false;
if(shortestPathFound)break;
} else {
queue.poll();
}
}
return shortestPath;
}
Run Code Online (Sandbox Code Playgroud)
我需要追踪BFS算法的节点.遍历到达节点6,就像[0,3,2,5,6].为此我创建了一个名为shortestPath&尝试存储受访节点的先前节点的List ,以获取节点列表.简称
但它似乎没有用.最短的路径是[0,3,2,5,6]
在列表中我得到的是 Shortest path: [0, 0, 0, 0, 1, 3, 3, 2, 5]
这部分是正确的,但给了额外的1.
如果我再次从第一个元素开始0的的shortestPath名单和启动遍历和回溯.就像1不具备优势来3,所以我原路返回&摆脱0到3到5,我会得到答案,但不知道这是正确的做法.
获取最短路径节点的理想方法是什么?
将所有访问的节点存储在单个列表中对于找到最短路径没有帮助,因为最终您无法知道哪些节点是导致目标节点的节点,哪些节点是死角.
您需要做的是每个节点将前一个节点存储在起始节点的路径中.
所以,创建一个地图Map<Integer, Integer> parentNodes,而不是这个:
shortestPath.add(nextNode);
Run Code Online (Sandbox Code Playgroud)
做这个:
parentNodes.put(unvisitedNode, nextNode);
Run Code Online (Sandbox Code Playgroud)
到达目标节点后,您可以遍历该映射以查找返回到起始节点的路径:
if(shortestPathFound) {
List<Integer> shortestPath = new ArrayList<>();
Integer node = nodeToBeFound;
while(node != null) {
shortestPath.add(node)
node = parentNodes.get(node);
}
Collections.reverse(shortestPath);
}
Run Code Online (Sandbox Code Playgroud)
正如你在acheron55 的回答中看到的:
“它有一个非常有用的特性,如果图中的所有边都未加权(或相同的权重),那么第一次访问节点时是从源节点到该节点的最短路径”
因此,您所要做的就是跟踪到达目标的路径。一个简单的方法是推入Queue用于到达节点的整个路径,而不是节点本身。
这样做的好处是,当到达目标时,队列会保留用于到达它的路径。
这是一个简单的实现:
/**
* unlike common bfs implementation queue does not hold a nodes, but rather collections
* of nodes. each collection represents the path through which a certain node has
* been reached, the node being the last element in that collection
*/
private Queue<List<Node>> queue;
//a collection of visited nodes
private Set<Node> visited;
public boolean bfs(Node node) {
if(node == null){ return false; }
queue = new LinkedList<>(); //initialize queue
visited = new HashSet<>(); //initialize visited log
//a collection to hold the path through which a node has been reached
//the node it self is the last element in that collection
List<Node> pathToNode = new ArrayList<>();
pathToNode.add(node);
queue.add(pathToNode);
while (! queue.isEmpty()) {
pathToNode = queue.poll();
//get node (last element) from queue
node = pathToNode.get(pathToNode.size()-1);
if(isSolved(node)) {
//print path
System.out.println(pathToNode);
return true;
}
//loop over neighbors
for(Node nextNode : getNeighbors(node)){
if(! isVisited(nextNode)) {
//create a new collection representing the path to nextNode
List<Node> pathToNextNode = new ArrayList<>(pathToNode);
pathToNextNode.add(nextNode);
queue.add(pathToNextNode); //add collection to the queue
}
}
}
return false;
}
private List<Node> getNeighbors(Node node) {/* TODO implement*/ return null;}
private boolean isSolved(Node node) {/* TODO implement*/ return false;}
private boolean isVisited(Node node) {
if(visited.contains(node)) { return true;}
visited.add(node);
return false;
}
Run Code Online (Sandbox Code Playgroud)
这也适用于循环图,其中一个节点可以有多个父节点。
| 归档时间: |
|
| 查看次数: |
14250 次 |
| 最近记录: |