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

时间:2009-11-19 14:26:20

标签: 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次,因为我们必须添加所有顶点)

我的结论是运行时间是: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;
}

2 个答案:

答案 0 :(得分:2)

您可以使用邻接列表来加速解决方案(但不能用于密集图表),但即便如此,如果没有Fibonacci堆,您也不会得到O(V log V)..

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

  • 将所有边插入数组并按重量对其进行排序
  • 对排序的边进行迭代,对于连接节点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初始化为全-1,然后每次想要找出节点A和B是否连接时,只需比较它们的父节点 - 如果它们相同,则它们是连接的(如下所示{ {1}})。当您将边缘插入MST时,请务必使用getParent(A)==getParent(B)更新Union-Find。

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

就是这样; - )

答案 1 :(得分:1)

之前我没有必要处理算法,但是你实现的算法与Wikipedia中解释的算法不匹配。该算法的工作原理如下。

  1. 但所有顶点都进入队列。 O(V)
  2. 队列不为空时... O(V)
    1. 从队列中获取最小权重的边缘。为O(log(V))
    2. 更新相邻顶点的权重。 O(E / V),这是相邻顶点的平均数。
    3. 重新建立队列结构。为O(log(V))
  3. 这给出了

            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)
    

    正是人们所期待的。