使用Dijkstra算法和unordered_map图

时间:2013-12-10 19:01:38

标签: c++ algorithm graph map dijkstra

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

// 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)。如果两个节点是相同的顶点(“波士顿”,“波士顿”),则该函数应返回0.

示例图 Example Graph

左侧的以下两个顶点的接近程度将在右侧:

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的确切描述方式,但我得到的读数不正确,我一直试图解决这个问题 - &gt;有人能指出我正确的方向吗?

3 个答案:

答案 0 :(得分:1)

这肯定不是问题的真正答案(因为我没有指出你关于你的实现的方向),但你是否考虑过只使用Boost Graph库? / p>

归结为为你的图形结构编写一个简短的Traits类(因此没有必要改变你的图形定义/标题),并且 - 至少对于这些基本算法 - 被证明是稳定且正确的。 / p>

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

答案 1 :(得分:0)

Palo Alto的问题 - &gt;波士顿似乎是算法采用路由Palo Alto -> San Fransisco -> Los Angeles -> San Fransisco(edgesTaken = 3)然后失败,因为San Fransisco已经被访问了。

答案 2 :(得分:0)

您的实施是错误的,只有偶然的机会才能获得“正确”的结果。

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

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)

你可以通过跟随前辈来获得路径长度。