图形遍历 - 查找并返回最短距离

时间:2013-08-21 14:26:13

标签: java graph queue traversal breadth-first-search

我在一个程序中使用广度优先搜索,该程序试图在未加权的有向图上找到并返回两个节点之间的最短路径。

我的程序就像维基百科页面的伪代码

该算法使用队列数据结构在遍历图形时存储中间结果,如下所示: 将根节点排入队列 将节点出列并检查它 如果在此节点中找到所寻找的元素,则退出搜索并返回结果。 否则将任何尚未发现的后继者(直接子节点)排入队列。 如果队列为空,则已检查图上的每个节点 - 退出搜索并返回“未找到”。 如果队列不为空,请从步骤2开始重复。

所以我一直在考虑如何跟踪所做的步骤数,但我遇到了java的局限性问题(我对java的工作方式不是很了解)。我原本以为我可以创建一些由我制作的存储步骤和节点的数据类型组成的队列,并且当它遍历图形时,它会跟踪步骤。如果达到目标,只需返回步骤。

我不知道如何在java中完成这项工作,所以我不得不摆脱这个想法,然后我继续使用那个不稳定的Queue =队列的新LinkedList实现。所以基本上我认为它是一个普通的整数队列,我无法获得我使用它的数据类型。

所以现在我必须找到一个更基本的方法,所以我尝试使用一个简单的计数器,这不起作用,因为遍历算法在到达最短路径之前搜索许多路径,所以我有一个想法。我添加了第二个跟踪步骤的队列,并添加了几个计数器。每当一个节点被添加到第一个队列时,我就会添加到计数器中,这意味着我知道我正在检查新节点,所以我距离不远。一旦检查了所有这些,我就可以增加步数计数器,并且每当将节点添加到第一个队列时,我就将步骤值添加到步骤队列中。步骤队列的管理方式与节点队列类似,因此当找到目标节点时,相应的步骤应该是要出列的步骤。

虽然这不起作用,但我遇到了很多问题,实际上我不确定原因。

我在恐慌和挫折中删除了大部分代码但是我会开始尝试重新创建并在此处发布,如果有人需要我的话。

我的任何想法都关闭了,我怎样才能让它们发挥作用?我确信有一个标准而简单的方法可以做到这一点,我不够聪明。

2 个答案:

答案 0 :(得分:1)

代码会有所帮助。您使用什么数据结构来存储部分或候选解决方案?您说您使用队列来存储要检查的节点,但实际上存储在队列中的对象应该包含一些结构(例如List),该结构指示遍历的节点到达要检查的节点。因此,不需要将简单的Node存储在队列中,而是需要一些更复杂的对象来提供知道到达该点的完整路径所必需的信息。一个简单的节点只有自己的信息,而且它是孩子。但是如果你正在检查节点X,你还需要知道你是如何到达节点X的。只知道节点X是不够的,并且知道路径X的路径的唯一方法(我知道)是存储对象中表示“部分解决方案”或“候选解决方案”的路径。如果这样做,那么找到路径的长度是微不足道的,因为它只是这个列表的长度(或者选择的数据结构)。希望我在这里有所作为。如果没有,请发布代码,我会看看。

修改

这些代码有助于显示我的意思(它们并非完整):

public class Solution {
    List<Node> path;
}

Queue<Solution> q;

不是

Queue<Node> q;

编辑2

如果你需要的只是路径的长度而不是路径本身,那么尝试这样的事情:

public class Solution {
    Node node; // whatever represents a node in you algorithm.
    int len; // the length of the path to this node.
}

// Your queue:
LinkedList<Solution> q;

有了这个,在排队候选解决方案(节点)之前,你会做类似的事情:

Solution sol = new Solution();
sol.node = childNodeToEnqueue;
sol.len = parentNode.len + 1;
q.add(sol);

答案 1 :(得分:0)

为了在遍历期间跟踪距离,最简单的解决方案是添加一个简单的数组(如果顶点没有用整数索引,则添加一个地图)。

这是伪代码算法:

shortest_path(g, src, dst):
  q = new empty queue
  distances = int array of length order of g
  for i = 0 to order: distances[i] = -1
  distances[src] = 0
  enqueue src in q
  while q is not empty:
    cur = pop next element in q
    if cur is dst: return distances[dst]
    foreach s in successors of cur in g:
      if distances[s] == -1:
        distances[s] = distances[cur] + 1
        enqueue s in q
  return not found

注意:图表的顺序是顶点数

您不需要特殊的数据结构,队列只能包含顶点&#39; id(可能是整数)。在Java中,LinkedList类实现了Queue接口,因此它是队列的一个很好的候选者。对于距离数组,如果您的顶点由整数标识,则整数数组就足够了,否则您需要一种地图。

你也可以使用一个单独的布尔数组或一组来分离顶点污点(我的算法中的-1),但它并不是必需的,并且会浪费一些空间。

如果你想要路径,你也可以用一个简单的父数组来做:对于你在遍历中存储它的父节点的每个顶点,只需在你的后继者入队时添加父[s] = cur。然后检索路径(以相反的顺序)是这样的简单:

path = new empty stack
cur = dst
while cur != src:
  push cur in path
  cur = parent[cur]
push src in path

你就是......