【问题标题】:Performance of Dijkstra's algorithm implementationDijkstra 算法实现的性能
【发布时间】:2011-09-13 05:34:28
【问题描述】:

下面是我根据Wikipedia article 中的伪代码编写的 Dijkstra 算法的实现。对于具有大约 40 000 个节点和 80 000 条边的图,运行需要 3 或 4 分钟。这是正确的数量级吗?如果不是,我的实现有什么问题?

struct DijkstraVertex {
  int index;
  vector<int> adj;
  vector<double> weights;
  double dist;
  int prev;
  bool opt;
  DijkstraVertex(int vertexIndex, vector<int> adjacentVertices, vector<double> edgeWeights) {
    index = vertexIndex;
    adj = adjacentVertices;
    weights = edgeWeights;
    dist = numeric_limits<double>::infinity();
    prev = -1; // "undefined" node
    opt = false; // unoptimized node
   }
};

void dijsktra(vector<DijkstraVertex*> graph, int source, vector<double> &dist, vector<int> &prev) {
  vector<DijkstraVertex*> Q(G); // set of unoptimized nodes
  G[source]->dist = 0;
  while (!Q.empty()) {
    sort(Q.begin(), Q.end(), dijkstraDistComp); // sort nodes in Q by dist from source
    DijkstraVertex* u = Q.front(); // u = node in Q with lowest dist
    u->opt = true;
    Q.erase(Q.begin());
    if (u->dist == numeric_limits<double>::infinity()) {
      break; // all remaining vertices are inaccessible from the source
    }
    for (int i = 0; i < (signed)u->adj.size(); i++) { // for each neighbour of u not in Q
    DijkstraVertex* v = G[u->adj[i]];
    if (!v->opt) {
      double alt = u->dist + u->weights[i];
      if (alt < v->dist) {
        v->dist = alt;
        v->prev = u->index;
      }
    }
    }
  }
  for (int i = 0; i < (signed)G.size(); i++) {
    assert(G[i] != NULL);
    dist.push_back(G[i]->dist); // transfer data to dist for output
    prev.push_back(G[i]->prev); // transfer data to prev for output
  }  
}

【问题讨论】:

    标签: c++ performance implementation dijkstra


    【解决方案1】:

    使用priority_queue。

    我的 Dijkstra 实现:

    struct edge
    {
        int v,w;
        edge(int _w,int _v):w(_w),v(_v){}
    };
    vector<vector<edge> > g;
    enum color {white,gray,black};
    vector<int> dijkstra(int s)
    {
        int n=g.size();
        vector<int> d(n,-1);
        vector<color> c(n,white);
        d[s]=0;
        c[s]=gray;
        priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q; // declare priority_queue
        q.push(make_pair(d[s],s)); //push starting vertex
        while(!q.empty())
        {
            int u=q.top().second;q.pop(); //pop vertex from queue
            if(c[u]==black)continue;
            c[u]=black; 
            for(int i=0;i<g[u].size();i++)
            {
                int v=g[u][i].v,w=g[u][i].w;
                if(c[v]==white) //new vertex found
                {
                    d[v]=d[u]+w;
                    c[v]=gray;
                    q.push(make_pair(d[v],v)); //add vertex to queue
                }
                else if(c[v]==gray && d[v]>d[u]+w) //shorter path to gray vertex found
                {
                    d[v]=d[u]+w;
                    q.push(make_pair(d[v],v)); //push this vertex to queue
                }
            }
        }
        return d;
    }
    

    【讨论】:

    • 我知道这篇文章有点老了。但是我没有得到你想要通过 g[u].size() 实现的目标。你是否试图扫描 g 的邻接列表。
    • g[u].size() 是与顶点 u 相连的顶点数。
    【解决方案2】:

    您可以改进以下几点:

    • 使用排序和擦除实现优先级队列会增加一个因子 |E|到运行时 - 使用 STL 的 heap functions 将 log(N) 插入和删除到队列中。
    • 不要一次将所有节点放入队列,而仅将那些您发现a路径的节点(这可能是也可能不是最佳的,因为您可以通过以下节点找到间接路径队列)。
    • 为每个节点创建对象会产生不必要的内存碎片。如果您关心挤出最后 5-10%,您可以考虑将关联矩阵和其他信息直接表示为数组的解决方案。

    【讨论】:

    • 感谢您的回复。我的印象是,我当前的实现并不是非常糟糕,并且根据您的建议,对于 40 000 个节点的问题,我可能预计执行时间为 1 到 3 分钟。接近 30 秒或 1 秒的执行时间是不合理的。这是真的吗?
    猜你喜欢
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 2019-07-31
    • 2021-04-21
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多