C++ 最有效地实施Dijkstra';在C++;stl

C++ 最有效地实施Dijkstra';在C++;stl,c++,algorithm,vector,stl,dijkstra,C++,Algorithm,Vector,Stl,Dijkstra,如果std::vector v(n)表示图的邻接列表,而pair是{vertex,weight}对,则我尝试以下方式实现该算法: while (true) { long long yo = LLONG_MAX; int ind = -1; for (int i = 0; i < n; ++i) { if (ans[i] < yo && !v[i].empty()) { ind =

如果
std::vector v(n)
表示图的邻接列表,而
pair
{vertex,weight}
对,则我尝试以下方式实现该算法:

while (true)
{
    long long yo = LLONG_MAX;
    int ind = -1;
    for (int i = 0; i < n; ++i)
    {
        if (ans[i] < yo && !v[i].empty())
        {
            ind = i;
            yo = ans[i];
        }
    }
    if (ind == -1)
        break;
    for (int i = 0; i < v[ind].size(); ++i)
    {
        if (ans[v[ind][i].first] > ans[ind] + v[ind][i].second)
            ans[v[ind][i].first] = ans[ind] + v[ind][i].second;
        v[ind].erase(v[ind].begin() + i);
    }
}
while(true)
{
long long yo=LLONG_MAX;
int ind=-1;
对于(int i=0;ians[ind]+v[ind][i].second)
ans[v[ind][i]。第一]=ans[ind]+v[ind][i]。第二;
v[ind].erase(v[ind].begin()+i);
}
}

其中,
ans[i]
存储初始化为
{LLONG_MAX,…0,…LLONG_MAX}
0
作为源的最短路径。由于这是我第一次尝试实现它,有没有更好的方法在stl中使用向量/列表来实现(可能在时间/空间复杂性方面)?

当前方法存在逻辑缺陷(在迭代向量时修改向量)。 同样从复杂性的角度来看,它看起来也很糟糕,因为每次都会重复while循环以获得新的最小距离节点,并且不需要执行擦除操作,由于整个邻接列表的移动,该操作的向量很重

我建议使用优先级队列,它更干净,复杂性为Elog(N),其中E是图中的边数,N是节点数。 我只是复制粘贴我的一个带有注释的旧代码

#define P first
#define Q second 
typedef long long LL ;
typedef pair < LL , int > li ;
typedef pair < int , LL > il ;
dist[N] = {INT_MAX} ;  // array containing the distance to each node from source node 
vector < il > adj [100010] ; // adjacency list with (node, distance) pair 

void dijkstra( int s ){   // s is the source node
  priority_queue < li , vector < li > , greater < li > > pq; // priortiy queue with a pair <long, int> as the data , using vector as underlying data structure and std:greater comparator 
  dist [s] = 0;
  pq.push( li( dist[s], s) );
  while( !pq.empty() ){
      li u = pq.top() ; pq.pop() ; // u.P =  current minimum distance of node , u.Q = current node on top of the heap 
      if( dist[u.Q] == u.P )
      for( int i = 0 ; i  < adj[u.Q].size() ; i++){
           il v = adj[u.Q][i] ;
           if( dist[v.P] > u.P + v.Q ){
               dist[v.P] = u.P + v.Q ;
               pq.push( li(dis[v.P] ,v.P ));
           }
      } 
  }
#首先定义P
#定义Q秒
typedef long-long-LL;
typedef对li;
typedef对il;
dist[N]={INT_MAX};//包含每个节点到源节点的距离的数组
向量adj[100010];//具有(节点、距离)对的邻接列表
void dijkstra(int s){//s是源节点
优先级队列,更大的
  • >pq;//使用向量作为底层数据结构和std:greater comparator的一对作为数据的优先级队列 距离[s]=0; 质量推送(li(距离[s],s)); 而(!pq.empty()){ li u=pq.top();pq.pop();//u.P=节点的当前最小距离,u.Q=堆顶部的当前节点 如果(距离[u.Q]==u.P) 对于(int i=0;iu.P+v.Q){ dist[v.P]=u.P+v.Q; 质量推送(li(dis[v.P],v.P)); } } }

  • 如果您有任何问题,请随时发表评论。

    一些优化Dijkstra的方法:

    #define P first
    #define Q second 
    typedef long long LL ;
    typedef pair < LL , int > li ;
    typedef pair < int , LL > il ;
    dist[N] = {INT_MAX} ;  // array containing the distance to each node from source node 
    vector < il > adj [100010] ; // adjacency list with (node, distance) pair 
    
    void dijkstra( int s ){   // s is the source node
      priority_queue < li , vector < li > , greater < li > > pq; // priortiy queue with a pair <long, int> as the data , using vector as underlying data structure and std:greater comparator 
      dist [s] = 0;
      pq.push( li( dist[s], s) );
      while( !pq.empty() ){
          li u = pq.top() ; pq.pop() ; // u.P =  current minimum distance of node , u.Q = current node on top of the heap 
          if( dist[u.Q] == u.P )
          for( int i = 0 ; i  < adj[u.Q].size() ; i++){
               il v = adj[u.Q][i] ;
               if( dist[v.P] > u.P + v.Q ){
                   dist[v.P] = u.P + v.Q ;
                   pq.push( li(dis[v.P] ,v.P ));
               }
          } 
      }
    
  • 使用堆。确保在堆中存储顶点,而不是边
  • 尝试双向方法。假设你必须找到从S到T的最短路径。你可以同时运行两个Dijkstra:一个像往常一样从S运行,另一个从T运行在反向边上。你可以使用某种启发式在这两个Dijkstra之间切换。例如,使用电流半径最小的Dijkstra

  • 理论上,Dijkstra可以用Fibonacci堆优化为O(E+VlogV)。但实际上它的工作速度较慢。

    这个问题可能更适合,因为它似乎是关于已经工作的代码。“更好”在什么方面?速度?内存使用?我个人最看重可读性;)@tobi303时间和内存usage@yobro97如果您想使用向量向量优化时间和内存使用,则已经失败。我认为
    v[ind].erase(v[ind].begin()+I);
    是错误的(因为您在向量的迭代过程中以一种奇怪的方式修改了向量)。