实现Dijkstra算法

时间:2010-05-24 18:17:36

标签: c++ dijkstra

我的任务是(课程作业@大学)实施一种寻路方式。现在,在规范中,我可以实现一个暴力,因为搜索的节点数量有限制(开始,两个在中间,结束),但我想重新使用这个代码并开始实现{ {3}}

我在维基百科上看过伪,一位朋友也为我写了一些,但它没有意义。算法看起来非常简单,对我来说理解它并不是一个问题,但我不能为我的生活想象出可以实现这种事情的代码。

有任何建议/提示吗?

编辑一些混淆:
是的,有一个目标节点和一个源节点。
我想在一般情况下实现Dijkstra,而不是“只有两个中间停止”的情况,因为我想在之后再次使用代码。另外,我只是写一个暴力实施 我遇到一些麻烦的具体问题是存储次优的半成形路径,以防它们变得最佳。当我访问一个给定节点时,我只是看不到我将如何更新通过它的所有连接。
更多编辑:
现在回顾几个答案,然后去吧。

真正的编辑: 我忘了提到一个严重的复杂问题,即任何两个顶点之间可能有不同的UINT_MAX距离。抱歉。事实上,我忘了处理这个问题的事实可能首先是该死的问题的原因,尽管解决方案:对我来说,选择最短的问题是显而易见的。难怪其他人对于距离变量的伪没有考虑我的可变距离。

6 个答案:

答案 0 :(得分:7)

以下是Dijkstra算法的高级细分:

您将所有顶点粘贴在优先级队列中,其中所有顶点的优先级(距离)为无穷大,除了之外的源顶点,其距离为零(源顶点为零距离自身,对吗?)。

弹出优先级队列。删除的顶点是距离源最短距离的顶点。显然,从队列中弹出的第一个顶点是源。好吧,调用弹出的顶点 v

查看 v 的每个邻居。它们的距离都大于 v 的距离(否则我们就已经从队列中弹出了它们,对吧?)。假设 v 的距离为3, v 有3个邻居 x (dist-from-source:5), y (dist-from-source:10)和 z (dist-from-source:infinity)。

现在我们查看 v 的每个邻居距离。假设它们是: x - 3, y - 2, z - 4.这意味着从源到的路径通过 v 的x 的距离为| v | + 3(3 + 3 = 6), y 的距离为5(3 + 2 = 5),z的距离为7(3 + 4 = 7)。

x v 的路径比 x 的当前最短路径长,所以我们忽略它。但是,通过 v y z 的路径比先前已知的最短路径短,因此我们更新它们。

在完成所有顶点之前,你一直这样做。在每个点,当您从优先级队列中弹出min时,您知道已找到到该顶点的最短路径,因为任何可能的较短路径必须通过距离小于 v 的顶点,这意味着我们已经从队列中弹出了它。

答案 1 :(得分:3)

如果你从来没有写过像这样的东西,那么用C ++实现Dijksta的算法是一个非常激烈的问题。阅读维基百科页面后,这里有一些让你入门的想法。

struct Vertex {
    int id;
    std::vector<int> neighbors;
    int dist_from_source;  // need some sentry value for "infinity"
    int prev;  // need some sentry value for "undefined"
};

这是基于伪代码的前几行。 Graph可以是std::vector<Vertex>,也可以通过某种方式识别两个顶点之间的距离。

8     u := vertex in Q with smallest dist[]

此行表示需要std::make_heap(不是priority_queue,我们稍后会看到)。为此创建一个单独的向量,因为我们需要添加和删除它。查看如何提供一个谓词,将顶点放在堆顶部的最低dist_from_source

12      for each neighbor v of u: // where v has not yet been removed from Q.

这就是我们不将priority_queue用于Q的原因。您需要了解v是否仍在Q中。 priority_queue不允许你这样做。

13        alt := dist[u] + dist_between(u, v)

现在您需要Graph附带的距离函数。你没有说明图形数据是如何定义的,所以你在这里有点自己。

17      return dist[]

此行仅表示返回生成最短路径所需的任何数据。它基本上是一组顶点,其中所有顶点都填充了prevdist_from_source

答案 2 :(得分:1)

我填入OP的Wikipedia article link给出了一个非常清晰简洁的描述,以及动画图形。

可能缺少的键(?)是在算法的每个步骤中,您可能正在更新连接到“当前”节点的每个节点的最短路径。对于你的四节点“钻石”情况,如果A是开始而D是结束,首先计算到B和C的距离,然后从B计算从A到D的距离,然后通过C进行计算。通过C的路径较短,那么“从A到D的最短路径”是通过C.如果通过C的路径较长,则最短路径经过B.这显然应该(?)扩展到更复杂的网络。 / p>

在OP上真正编辑两个节点之间有多少连接并不重要。实际上,这就是算法的要点,通过所有可能的路径检查所有连接。如果节点A和节点B通过两条道路连接,并且您想要最短的道路,不要担心更长的道路,只需扔掉它。始终尝试丢弃您知道与您的问题无关的数据。

答案 3 :(得分:1)

您需要的第一件事是表示图表的方式。通常,这是vertex个对象的集合,每个对象都包含一个邻接列表。在c ++中,这可能是指向其他顶点的指针列表。确保顶点是LessThanComparable。例如,您可以为每个人提供唯一的ID号。

然后,维基百科上的代码应该更有意义。每次有像dist[v]这样的伪代码时,都希望使用map<VertexIdNumber, double>

答案 4 :(得分:0)

  

我遇到一些麻烦的具体问题是存储次优的半成形路径,以防它们变得最佳。当我访问给定节点时,我只是看不到如何更新通过它的所有连接。

我想也许你对这个算法有点误解了。 Dijkstra通过以增加的距离顺序探索节点来工作;因此,您可以确保找到已永久标记的任何节点的最小距离和最佳路径。

运行算法时,通常不会显式存储任何路径。相反,请考虑您正在图形上构建生成树 - 因此只有一种方法可以到达该树上的每个节点。对每个节点存储的所有内容都是距离标签及其父节点。当您在搜索过程中第一次看到每个节点时,您将暂时标记它;以后你可能会找到更好的路径 - 但是你必须在那时更新的是该单个节点的距离和父标签。

永久标记目的地后,您可以停止,然后通过将父标签向上走回源来获得最佳路线。

希望有所帮助:)

答案 5 :(得分:-2)

这种回应对你来说可能为时已晚,但我提供它以防万一。对其他人有帮助。

首先,您需要澄清是否

  1. 节点之间的边缘具有不同的权重
  2. 图表是定向的还是非定向的
  3. 我在大学学习这样的算法已经25年了,但是从记忆中来看,Warshall算法更容易通过矩阵方法实现。你可以看一下:www.ugrad.cs.ubc.ca/~cs490/Spring05/notes/graph_part3.pdf]