Algorithm 最小生成树的运行时间?(Prim方法)

Algorithm 最小生成树的运行时间?(Prim方法),algorithm,performance,priority-queue,time-complexity,minimum-spanning-tree,Algorithm,Performance,Priority Queue,Time Complexity,Minimum Spanning Tree,我已经写了一段代码,用Prim方法解决了MST问题。我读到这种实现(使用优先级队列)应该有O(E+VlogV)=O(VlogV),其中E是边数,V是边数,但当我看我的代码时,它根本不是这样。如果有人能帮我澄清一下,我将不胜感激 在我看来,运行时间如下: while循环需要O(E)次(直到我们通过所有边) 在该循环中,我们从Q中提取一个元素,它需要O(logE)时间。 第二个内部循环需要O(V)时间(虽然我们不是每次都运行这个循环) 很明显,它将运行V次,因为我们必须添加所有顶点) 我的结论是运行

我已经写了一段代码,用Prim方法解决了MST问题。我读到这种实现(使用优先级队列)应该有O(E+VlogV)=O(VlogV),其中E是边数,V是边数,但当我看我的代码时,它根本不是这样。如果有人能帮我澄清一下,我将不胜感激

在我看来,运行时间如下:

while循环需要O(E)次(直到我们通过所有边) 在该循环中,我们从Q中提取一个元素,它需要O(logE)时间。 第二个内部循环需要O(V)时间(虽然我们不是每次都运行这个循环) 很明显,它将运行V次,因为我们必须添加所有顶点)

我的结论是运行时间是:O(E(logE+V))=O(E*V)

这是我的代码:

#define p_int pair < int, int >

int N, M; //N - nmb of vertices, M - nmb of edges
int graph[100][100] = { 0 }; //adj. matrix
bool in_tree[100] = { false }; //if a node if in the mst
priority_queue< p_int, vector < p_int >, greater < p_int > > Q; 
/*
keeps track of what is the smallest edge connecting a node in the mst tree and
a node outside the tree. First part of pair is the weight of the edge and the 
second is the node. We dont remember the parent node beaceuse we dont need it :-)
*/

int mst_prim()
{
 Q.push( make_pair( 0, 0 ) );

 int nconnected = 0;
 int mst_cost = 0;
 while( nconnected < N )
 {
      p_int node = Q.top(); Q.pop();

      if( in_tree[ node.second ] == false )
      {
           mst_cost += node.first;
           in_tree[ node.second ] = true;

           for( int i = 0; i < N; ++i )
                if( graph[ node.second ][i] > 0 && in_tree[i]== false )
                     Q.push( make_pair( graph[ node.second ][i], i ) );

           nconnected++;
      }
 }

 return mst_cost;
}
#定义p#u int对
int N,M//顶点的N-nmb,边的M-nmb
int图[100][100]={0}//形容词。矩阵
树[100]={false}中的布尔//如果一个节点在mst中
优先级队列,大于>Q;
/*
跟踪连接mst树中节点的最小边是什么,以及
树外的节点。该对的第一部分是边和边的重量
二是节点。我们不记得父节点beace,因为我们不需要它:-)
*/
int mst_prim()
{
Q.push(使_对(0,0));
int n连接=0;
int mst_成本=0;
while(已连接0&&in_树[i]==false)
Q.push(make_对(图[node.second][i],i));
连接的++;
}
}
返回mst_成本;
}

我以前不必处理该算法,但您所实现的与上解释的算法不匹配。那里的算法工作如下

  • 但所有顶点都会进入队列。O(V)
  • 当队列不为空时。。。O(V)
  • 从队列中取出重量最小的边。O(对数(V))
  • 更新相邻顶点的权重。O(E/V),这是相邻顶点的平均数
  • 重新建立队列结构。O(对数(V))
  • 这给

    O(V) + O(V) * (O(log(V)) + O(V/E)) = O(V) + O(V) * O(log(V)) + O(V) * O(E / V) = O(V) + O(V * log(V)) + O(E) = O(V * log(V)) + O(E) O(V)+O(V)*(O(log(V))+O(V/E)) =O(V)+O(V)*O(log(V))+O(V)*O(E/V) =O(V)+O(V*log(V))+O(E) =O(V*log(V))+O(E)
    这正是人们所期望的。

    您可以使用邻接列表来加快解决方案的速度(但对于密集图则不行),但即使如此,如果没有Fibonacci堆,您也无法得到O(V log V)

    也许你更容易理解。它没有优先级队列,您只需对一组边进行一次排序。基本上是这样的:

    • 将所有边插入数组并按权重排序
    • 迭代排序的边,对于连接节点i和j的每条边,检查i和j是否连接。如果是,则跳过边,否则将边添加到MST中
    唯一的问题是能够快速说出两个节点是否连接。为此,您使用Union Find数据结构,如下所示:

    int T[MAX_#_OF_NODES]
    
    int getParent(int a)
    {
      if (T[a]==-1)return a;
      return T[a]=getParent(T[a]);
    }
    void Unite(int a,int b)
    {
      if (rand()&1)
         T[a]=b;
      else
         T[b]=a;
    }
    
    在开始时,只需将T初始化为all-1,然后每次您想确定节点A和B是否连接时,只需比较它们的父节点-如果它们相同,则它们是连接的(如下
    getParent(A)==getParent(B)
    )。将边插入MST时,请确保使用
    Unite(getParent(A)、getParent(B))
    更新联合查找

    分析很简单,您可以对边进行排序,并使用取O(1)的UF进行迭代。所以是O(E logE+E)等于O(E logE)


    就这样;-)

    我不太确定是否要在开始时插入所有顶点。。。如何提取权重最小并连接到当前mst(我们当前正在构建)的顶点?每个顶点的优先级是连接顶点与当前生成树的成本-这是连接顶点与当前树的所有边的最小权重,如果没有边,则为无穷大。所有这些值都以无穷大初始化,并在每次顶点从队列移动到树时更新。我知道Kruskals算法,但我也想了解这个算法:-)。如果我对Prim使用邻接列表,那么我将得到:while+作为所有边上的循环,并将它们插入堆中。这应该是E*log(E)。这是使用这种方法(使用堆,而不是Fibbonaci堆)可以获得的最佳复杂性吗?是的,您最多检查两次每条边(来自两个节点),队列的最大边数为E,这导致O(E log E)。但我们并不是这样写的,因为常数因子在O()符号中是不相关的。所以O(E log E)=O(E log(V^2))=O(E*2 log V)=O(E log V)。这(上面的评论)是我想要的答案,谢谢我现在明白了:-)