【问题标题】:Finding shortest path between two nodes寻找两个节点之间的最短路径
【发布时间】:2021-10-23 03:57:47
【问题描述】:

我试图弄清楚如何制作一种方法来找到两个节点之间的最短路径,但似乎无法弄清楚。我得到了两个文件,一个包含演员(将是节点)的文件,另一个包含电影(将是边缘)。

我将图表示为 HashMap,其中键是演员,值是 ArrayList,其中包含演员出演过的电影:

HashMap<Actor, ArrayList[Movie]> graph;

现在我想找到两个演员之间的最短路径,但我不知道该怎么做。我在考虑 DFS 或 BFS,但我不太确定如何使用这个 hashmap 来做到这一点..

【问题讨论】:

  • 如果您在使用此 HashMap 时遇到问题,您是否考虑过使用不同的数据结构?
  • 不确定要使用什么其他数据结构...
  • 如果您创建另一个地图,其中包含作为键的演员和与任一演员的距离,您将能够找到距离。我知道这不是您正在寻找的确切答案,但它应该给您一个开始。在这个image中,我计算了每个节点到节点B的距离
  • 请提供足够的代码,以便其他人更好地理解或重现问题。
  • 我真的不明白你为什么要这样建模你的图表。对于基本的图问题,我们有两种建模方法:邻接列表邻接矩阵。如果你希望它是邻接列表,它应该是Map&lt;Actor, Set&lt;Actor&gt;&gt; graph;(我猜到了,因为你说电影是边缘)。 dijkstra 是一种著名的寻找最短路径的算法。 google上的实现很多,你可以试试。

标签: java


【解决方案1】:

可以使用您当前的结构 (HashMap&lt;Actor, ArrayList&lt;Movie&gt;&gt;) 作为邻接列表,但缺少一些东西:一种从电影返回到其中主演的演员的有效方法。你可以建立一个Map&lt;Movie, List&lt;Actor&gt;&gt;,这样就可以了……但是使用单个邻接列表更简单,而不是一个用于演员,另一个用于电影。我会这样做(假设ActorMovie都实现了equalshashcode,并且没有演员等于任何电影):

 Map<Object, List<Object>> edges = new HashMap<>();

 for (Map.Entry<Actor, ArrayList<Movie>> e : graph.entries()) {
     Actor a = e.getKey();         
     edges.put(a, new ArrayList<Object>(e.getValues()));
     for (Movie m : e.getValues()) {
         List<Actor> otherActors = edges.getOrDefault(m, new ArrayList<Object>());
         otherActors.add(a);
         edges.put(m, otherActors);
     }
 }

现在您可以使用edges 执行标准的广度优先搜索。保证为您提供任意 2 个演员之间的最短路径(可能有多个同样短的路径),并且该路径将包含链接他们的电影。

【讨论】:

  • 我看不到单个邻接列表将如何完成这项工作。当您执行 otherActors = getOrDefault 时它应该会失败,因为这两个列表包含不同类型的对象。
  • 如果边缘不是Map&lt;Object, List&lt;Object&gt;&gt; 类型,它将失败。 Actor 和 Movie 都是对象。
  • 具有 2 个不同邻接列表的 BFS 会迫使您根据深度从一个切换到另一个(actorToMovie,然后是 movieToActor,然后是 actorToMovie)。拥有一个邻接列表就可以消除这种麻烦。
【解决方案2】:

仅仅为您指明方向并不是完整的解决方案,您必须创建一个 Maptucuxi suggested。您将逐个遍历每个actor,并在当前actor上标记与您的参考actor的距离。

private static void fn(HashMap<Actor, List<Movie>> graph, Actor referenceActor) {
    var movieMap = new HashMap<Movie, List<Actor>>();
    graph.forEach((key, value) -> {
        for (var movie : value) {
            movieMap.compute(movie, (k, v) -> {
                if (v == null) {
                    return new ArrayList<>(List.of(key));
                }
                v.add(key);
                return v;
            });
        }
    });


    final var visited = new HashSet<Actor>();
    var dq = new ArrayDeque<Actor>();
    var map = new HashMap<Actor, Integer>();

    dq.add(referenceActor);
    int distance = 0;
    while (!dq.isEmpty()) {
        var size = dq.size();
        for (int i = 0; i < size; i++) {
            var actor = dq.poll();
            visited.add(actor);
            map.putIfAbsent(actor, distance);
            for (Movie movie : graph.get(actor)) {
                // adding every non visited actor in the same movie in the queue
                dq.addAll(movieMap
                        .get(movie)
                        .stream()
                        .filter(x -> !visited.contains(x))
                        .collect(Collectors.toList()));
            }
        }
        distance++;
    }
    System.out.println(map);
}

我在这里使用ArrayDeque 以 BFS 方式遍历,如果您希望 DFS 可以修改,请记住计算距离的逻辑也需要更改。粘贴image from the comments,将节点B作为参考actor。

【讨论】:

    猜你喜欢
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 1970-01-01
    • 2015-06-25
    • 2023-01-15
    • 2021-12-18
    相关资源
    最近更新 更多