[英]Find shortest path between two locations (Unweighted & Using BFS)
SHORTEST PATH USING BFS 使用BFS的最短路径
public static LinkedList<String> findShortestPath(String start, String end) {
LinkedList<String> bfsList = new LinkedList<String>();
Queue<Actor> queue = new LinkedList<Actor>();
Map<String, Actor> prev = new HashMap<String, Actor>();
Actor current = graph.getActorsByName().get(start);
queue.add(current);
current.setVisited(true);
while(!queue.isEmpty()) {
current = queue.remove();;
if(current.getName().equals(end)) {
break;
} else {
for(int i = 0; i < current.getFriends().size(); i++) {
if(current.getFriends().get(i).getVisited() == false) {
queue.add(graph.getActorsByName().get(current.getFriends().get(i).getName()));
graph.getActorsByName().get(current.getFriends().get(i).getName()).setVisited(true);
prev.put(current.getFriends().get(i).getName(), current);
}
}
}
}
if(!current.getName().equals(end)) {
System.out.println("\nThere is no path between " + start + " and " + end);
}
for(Map.Entry<String, Actor> entry : prev.entrySet()) {
String key = entry.getKey();
bfsList.add(key);
}
return bfsList;
}
Above is the code I'm using to try and find the shortest path between two points in a graph. 上面是我用来尝试找到图中两点之间最短路径的代码。 It isn't giving me the correct path between the two points, and I cannot figure out why. 这并没有给我两点之间的正确路径,我也不知道为什么。
I've set up a test rig, where I expect an actor to have a name and some friends. 我已经建立了一个测试平台,我希望一个演员有一个名字和一些朋友。 Those immediate friends also have a reciprocal relationship. 那些直接的朋友也有互惠的关系。
In this test I am looking for the shortest path between "james" and "mary". 在此测试中,我正在寻找“ james”和“ mary”之间的最短路径。
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import org.junit.Test;
public class ShortestPathTest {
Map<String, ShortestPath.Actor> graph = new HashMap<>();
private ShortestPath.Actor newActor(String name, String... friends) {
ShortestPath.Actor actor = graph.computeIfAbsent(name, k -> new ShortestPath.Actor(name));
for(String friendsName : friends) {
ShortestPath.Actor friend = newActor(friendsName);
actor.addFriend(friend);
friend.addFriend(actor);
}
return actor;
}
@Test
public void findShortestPath() {
newActor("james", "harry", "luke", "john");
newActor("harry", "luke", "mary");
LinkedList<String> shortestPath = ShortestPath.findShortestPath(graph, "james", "mary");
assertThat(shortestPath, equalTo(Arrays.asList("james", "harry", "mary")));
}
}
The result I received was not consistent with my expectations and for some reason "mary" is in the middle of the output: 我收到的结果与我的期望不一致,并且由于某种原因“玛丽”出现在输出的中间:
java.lang.AssertionError:
Expected: <[james, harry, mary]>
but: was <[luke, harry, mary, john]>
Comparing the algorithm you have referenced , I suspect the issue is in this part (of the referenced algorithm): 比较您参考的算法 ,我怀疑问题出在这部分(参考算法):
for(Node node = finish; node != null; node = prev.get(node)) {
directions.add(node);
}
directions.reverse();
In your implementation you have initialised prev = new HashMap<String, Actor>()
and you are then adding every visited node (not just the nodes to indicate the shortest path). 在实现中,您已初始化prev = new HashMap<String, Actor>()
,然后添加每个访问的节点(不仅仅是指示最短路径的节点)。 You need to use prev
as sort of linked list... for example: 您需要使用prev
作为链接列表的种类...例如:
for (Actor node = graph.get(end); node != null; node = prev.get(node.getName())) {
bfsList.add(node.getName());
}
Collections.reverse(bfsList);
Only minor edits applied to original posting: 仅对原始过帐进行了较小的修改:
graph
as parameter 输入graph
作为参数 code listing 代码清单
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
public class ShortestPath {
public static List<String> findShortestPath(Map<String, Actor> graph, String start,
String end) {
LinkedList<String> bfsList = new LinkedList<>();
Queue<Actor> queue = new LinkedList<>();
Map<String, Actor> prev = new HashMap<>();
Actor current = graph.get(start);
queue.add(current);
current.setVisited(true);
while (!queue.isEmpty()) {
current = queue.remove();
if (current.getName().equals(end)) {
break;
} else {
LinkedList<Actor> currentFriends = current.getFriends();
for (Actor currentFriend : currentFriends) {
if (!currentFriend.getVisited()) {
queue.add(currentFriend);
currentFriend.setVisited(true);
prev.put(currentFriend.getName(), current);
}
}
}
}
if (!current.getName().equals(end)) {
System.out.println("\nThere is no path between " + start + " and " + end);
return Collections.emptyList();
}
for (Actor node = graph.get(end); node != null; node = prev.get(node.getName())) {
bfsList.add(node.getName());
}
Collections.reverse(bfsList);
return bfsList;
}
static class Actor {
private final String name;
private final LinkedList<Actor> friends = new LinkedList<>();
private boolean visited;
Actor(String name) {
this.name = name;
}
public void setVisited(boolean visited) {
this.visited = visited;
}
// Would normally be `isVisited`
public boolean getVisited() {
return visited;
}
public String getName() {
return name;
}
public LinkedList<Actor> getFriends() {
return friends;
}
public void addFriend(Actor actor) {
this.friends.add(actor);
}
}
}
Builds test graph and asserts the correct path is found between various nodes 构建测试图并断言在各个节点之间找到正确的路径
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
public class ShortestPathTest {
Map<String, ShortestPath.Actor> graph = new HashMap<>();
@Before
public void setup() {
newActor("james", "harry", "luke", "john");
newActor("harry", "luke", "mary");
newActor("luke", "john", "hepzibah");
newActor("john", "kate");
newActor("mary", "hepzibah", "mia");
newActor("hepzibah", "richard");
newActor("kate", "martin", "mia");
newActor("mia", "susan");
newActor("richard", "rebecca");
newActor("rebecca", "hannah");
newActor("michelle");
}
private ShortestPath.Actor newActor(String name, String... friends) {
ShortestPath.Actor actor = graph.computeIfAbsent(name, k -> new ShortestPath.Actor(name));
for (String friendsName : friends) {
ShortestPath.Actor friend = newActor(friendsName);
actor.addFriend(friend);
friend.addFriend(actor);
}
return actor;
}
@Test
public void findShortestPath() {
List<String> shortestPath = ShortestPath.findShortestPath(graph, "james", "mary");
assertThat(shortestPath, equalTo(Arrays.asList("james", "harry", "mary")));
}
@Test
public void findLongerShortestPath() {
List<String> shortestPath = ShortestPath.findShortestPath(graph, "james", "mia");
assertThat(shortestPath, equalTo(Arrays.asList("james", "harry", "mary", "mia")));
}
@Test
public void findAnotherShortestPath() {
List<String> shortestPath = ShortestPath.findShortestPath(graph, "harry", "hannah");
assertThat(shortestPath, equalTo(Arrays.asList("harry", "luke", "hepzibah", "richard", "rebecca", "hannah")));
}
@Test
public void findNoPath() {
List<String> shortestPath = ShortestPath.findShortestPath(graph, "james", "michelle");
assertThat(shortestPath, equalTo(Collections.emptyList()));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.