这里简单讲解一下普利姆算法的实现
伪码如下:
1 color[n] color[v]用于记录v的访问状态WHITE(未访问顶点),GRAY(队列中的顶点),BLACK(访问结束的顶点) 2 M[n][n] 邻接矩阵,M[u][v]记录u到v的边的权值 3 d[n] d[v]用于记录连接T内顶点与V-T内顶点的边中,权值最小的边的权值 4 p[n] p[v]用于记录MST中顶点v的父节点 5 6 prim() 7 将所有顶点u的color[u]设置为WHITE,d[u]初始化为INFTY 8 d[0] = 0 9 p[0] = -1 10 11 while(true) 12 mincost = INFTY 13 // 扫描点集合,选出一个距离当前MST最近的点 14 for i 从 0 至 n-1 15 if color[i] != BLACK && d[i] < mincost 16 mincost = d[i] 17 u = i; 18 19 if mincost == INFTY 20 break 21 22 color[u] = BLACK 23 24 // 选出点后,扩展MST,并更新其他点到MST的距离 25 for v 从 0 至 n-1 26 if color[v] != BLACK且u和v之间存在边 27 if M[u][v] < d[v] 28 d[v] = M[u][v] 29 p[v] = u 30 color[v] = GRAY 31
实现过程简述:
初始时刻,MST为空集
设置0节点到MST的距离为0
则第一次选离MST最近的节点一定是0节点
选中0节点之后,MST得到扩展,此时用0节点更新其他节点到MST的距离
这个意思就是说,每次选中一个节点过后,MST扩充了这个新节点,其他节点到MST的距离要更新,而这里所谓的其他节点,其实就是新节点的近邻
因为其他和新节点无关的节点,到MST的距离已经在之前就更新过了,所以这里只需要更新新节点的近邻就行
然后循环,在更新距离过后的新距离向量里选取最近节点,直到所有节点选完,跳出循环
这里p数组,用来记录MST中父节点信息,在计算MST最小权值是没用的,但是在生成MST和相关的信息查询时会起到很大作用
上述算法实现的时间复杂度是O(V²)
优化:
用二叉堆/优先队列来选择边,可以提高算法时间效率
每次选择新边不用再扫一遍所有点集合了,直接从二叉堆里取最小边即可,用最小堆优化的时间复杂度是O(VlogV + ElogV),使用斐波那契堆优化O(E + VlogV)。
这里使用邻接表的效率比邻接矩阵高,因为在新节点加入MST后,要扫新节点的邻近节点,邻接表就可以直接拿到,邻接矩阵得扫所有节点