【问题标题】:Using Dijkstra's algorithm with an unordered_map graph将 Dijkstra 算法与 unordered_map 图一起使用
【发布时间】:2013-12-10 19:01:38
【问题描述】:

所以这是我当前的代码,我将在下面发布标题声明...

// Using Dijkstra's
int Graph::closeness(string v1, string v2){
int edgesTaken = 0;
unordered_map<string, bool> visited;
unordered_map<string, int> distances;
string source = v1; // Starting node
while(source != v2 && !visited[source]){
    // The node has been visited
    visited[source] = 1;
    // Set all initial distances to infinity
    for(auto i = vertices.begin(); i != vertices.end(); i++){
        distances[i->first] = INT_MAX;
    }
    // Consider all neighbors and calculate distances from the current node
    // & store them in the distances map
    for(int i = 0; i < vertices[source].edges.size(); i++){
        string neighbor = vertices[source].edges[i].name;           
        distances[neighbor] = vertices[source].edges[i].weight; 
    }   
    // Find the neighbor with the least distance
    int minDistance = INT_MAX;
    string nodeWithMin;
    for(auto i = distances.begin(); i != distances.end(); i++){
        int currDistance = i->second;
        if(currDistance < minDistance){
            minDistance = currDistance;
            nodeWithMin = i->first;
        }       
    }
    // There are no neighbors and the node hasn't been found yet
    // then terminate the function and return -1. The nodes aren't connected
    if(minDistance == INT_MAX) 
        return -1;
    // Set source to the neighbor that has the shortest distance
    source = nodeWithMin;
    // Increment edgesTaken
    edgesTaken++;
    // clear the distances map to prepare for the next iteration
    distances.clear();
}
return edgesTaken;
}

声明(这是一个无向图):

class Graph{
    private:
            // This holds the connected name and the corresponding we
            struct EdgeInfo{
                    std::string name;
                    int weight;
                    EdgeInfo() { }
                    EdgeInfo(std::string n, int w) : name(n), weight(
            };

            // This will hold the data members of the vertices, inclu
            struct VertexInfo{
                    float value;
                    std::vector<EdgeInfo> edges;
                    VertexInfo() { }
                    VertexInfo(float v) : value(v) { }
            };

            // A map is used so that the name is used as the index
            std::unordered_map<std::string, VertexInfo> vertices;

注意:请不要建议我更改标头声明,我正在为一个已经编写了 8 个其他函数的项目做出贡献,现在返回并更改任何内容肯定为时已晚,因为那时所有其他函数都会必须重写

我目前得到的输出不正确。但是,该函数正确处理 0 距离情况(如果两个顶点未连接,则该函数应返回 -1)。如果两个节点是相同的顶点 ex closeness("Boston", "Boston") 那么函数应该返回一个 0。

示例图

左边以下两个顶点的接近度会在右边:

Correct:
Trenton -> Philadelphia: 2
Binghamton -> San Francisco: -1
Boston -> Boston: 0
Palo Alto -> Boston: -1

Output of my function:
Trenton -> Philadelphia: 3
Binghamton -> San Francisco: -1
Boston -> Boston: 0
Palo Alto -> Boston: 3

我试图复制 dijkstra 的确切描述方式,但我得到的读数不正确,我一直试图弄清楚这一点 -> 谁能指出我正确的方向?

【问题讨论】:

  • 对我来说特伦顿 - > 费城真的是 3 条边长,因为 3+2+10
  • 有很多问题。首先,您的算法并没有真正跟踪所有可达节点,因此它只是沿着任何给定节点的最短路径移动,而不考虑总路径长度。其次,返回是返回总距离,但上面的“正确”结果是路径中的顶点总数。你要哪个?
  • 我已经编辑了我的代码。该算法需要输出从顶点 v1 到顶点 v2 所需的最小边数。正如您在图表中所看到的@Johan,从特伦顿 -> 费城只需 2 次跳跃
  • 您是否尝试过打印出每个节点的邻居列表以确保数据正确?
  • 是的,但是你的边被加权了,你实际上使用这个权重来计算最短路径......

标签: c++ algorithm dictionary graph dijkstra


【解决方案1】:

这肯定不是问题的真正答案(因为我没有为您指明有关您的实现的方向),但您是否考虑过仅使用 Boost Graph 库?

归结为为您的图形结构编写一个简短的 Traits 类(因此没有必要更改您的图形定义/标题)并且 - 至少对于这些基本算法 - 被证明可以稳定且正确地工作。

我总是建议不要重新发明轮子,尤其是在图形和数字方面...

【讨论】:

  • 1:在这种情况下,Boost Graph 库对我有什么用处 2:Traits 类的成员是什么?
  • 1.我已经更深入地研究了 Boost Graph 中 Dijktstra 算法所需的概念,在这种情况下,如果你不打算在你的图结构上实现任何其他算法,你最好修复自己的代码并注意对于讨厌的特殊情况。如果您预计在不久的将来会针对这种结构破解大量图形算法,那么通常值得研究 Boost Graph。 2. Traits 类将定义您的顶点和边类型(后者是我对 1 的回答的原因)、它们的迭代器以及这些迭代器的访问函数。
【解决方案2】:

你的实现是错误的,你得到“正确”的结果只是偶然。

让我们亲手做一个例子。从特伦顿到费城。我使用城市的第一个字母作为标签。

First iteration
visited = [(T, 1), (N, 0), (W, 0), (P, 0), (B, 0)]
minDistance = 3;
nodeWithMin = N;
edgesTaken = 1

second iteration
visited = [(T, 1), (N, 1), (W, 0), (P, 0), (B, 0)]
minDistance = 2;
nodeWithMin = W;
edgesTaken = 2

third iteration
visited = [(T, 1), (N, 1), (W, 1), (P, 0), (B, 0)]
minDistance = 2;
nodeWithMin = N;
edgesTaken = 3;

fourth iteration
N is already 1 so we stop. Can you see the errors?

传统上 Dijkstras 最短路径算法是通过优先级队列实现的

dijkstra(graph, source)
    weights is a map indexed by nodes with all weights = infinity
    predecessor is a map indexed by nodes with all predecessors set to itself
    unvisited is a priority queue containing all nodes

    weights[source] = 0
    unvisited.increase(source)

    while unvisited is not empty
      current = unvisited.pop();
      for each neighbour to current
        if weights[current] + edge_weight(current, neighbour) < weights[neighbour]
          weights[neighbour] = weights[current] + + edge_weight(current, neighbour)
          unvisited.increase(neighbour)
          predecessors[neighbour] = current

    return (weights, predecessors)

而且你可以按照前人的方法得到路径长度。

【讨论】:

  • 这比我的导师提供的关于 Dijkstra 工作原理的说明要好得多...谢谢
【解决方案3】:

Palo Alto -> Boston 的问题似乎是该算法采用路线 Palo Alto -&gt; San Fransisco -&gt; Los Angeles -&gt; San Fransisco (edgesTaken = 3),然后由于已经访问过旧金山而导致 while 条件失败。

【讨论】:

  • 对....你知道我如何处理断开的顶点比我的代码当前处理它的方式更好吗?
  • 别想了:使用 bool(bFound 或其他,初始化为 false),当 source == v2 时可以设置为 true。退出循环后检查该值:if(!bFound) return -1;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多