最小生成树之Prim算法

Posted 浪漫逆风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树之Prim算法相关的知识,希望对你有一定的参考价值。

本博客的代码的思想和图片参考:好大学慕课浙江大学陈越老师、何钦铭老师的《数据结构》

1 最小生成树的概念

最小生成树的概念:是由图生成而来的

是一棵树

1.无回路

2.如果有V个定点就有V-1条边

是生成树

1.包含图中所有的节点V

2.V-1条边都在图里面

3.边的权重和最小。

4.向生成树中添加任意一条边都构成回路。


2 算法思想:贪心算法

“贪”:每一步都要最好的。

“好”:权重最小的边

约束条件:

1.只能使用图里面的边

2.只能正好使用V-1条边

3.不能有回路


3 Prim算法—让一棵小树慢慢长大

3.1算法思想:

1.先选择一个顶点作为树的根节点,把这个根节点当成一棵树

2.选择图中距离这棵树最近但是没有被树收录的一个顶点,把他收录在树中,并且保证不构成回路

3.按照这样的方法,把所有的图的顶点一一收录进树中。

4.如果没有顶点可以收录

a.如果图中的顶点数量等于树的顶点数量-->最小生成树构造完成

b. 如果图中的顶点数量不等于树的顶点数量-->此图不连通

下面使用图片来具体描述此算法的算法思想:


 3.2Prim算法的伪代码描述

通过我们对算法的描述,我们发现Prim算法和Dijkstra算法很类似

void Prim()

{

  MST = {s};

while (1) {

V = 未收录顶点中dist最小者;

if ( 这样的V不存在 )

break;

V收录进MST: dist[V] = 0;

for ( V 的每个邻接点 W )

if ( dist[W]!=W未被收录 0 )

if ( E (V,W) < dist[W] ){

dist[W] = E (V,W) ;

parent[W] = V;

}

}

if ( MST中收的顶点不到|V|)

Error ( “生成树不存在” );

}

对于Prim算法

1.dist代表的是什么,应该如何被初始化

dist代表距离当前生成树的最小距离。和根节点直接相邻的初始化为权重,其他的初始化为正无穷。等每插入一个树节点,对dist进行更新。对于已经收录的节点,更新其dist=0

2.该算法的时间复杂度是多少

该算法时间复杂度在于如何去 ”未收录顶点中dist最小者”如果是使用暴力搜索的方法,那么时间复杂的为T=O(n^2).此种算法对于稠密图比较适用。

 

4 Kruskal 算法—将树合并成森林

4.1 算法思想

使用贪心算法,每次获取权重最小的边,但是不能让生成树构成回路。直到去到V-1条边为止。

下面还是使用一个图来说明次算法

 

 

伪代码描述



void Kruskal ( Graph G )

{

MST = { } ;

while ( MST 中不到 |V| 1 条边 && E 中还有边 ) {

E 中取一条权重最小的边 E (v,w) ; /* 最小堆 */

E (v,w) E 中删除;

if ( E (V,W) 不在 MST 中构成回路) /* 并查集 */

E (V,W) 加入 MST;

else

彻底无视 E (V,W) ;

}

}

if ( MST 中不到 |V| 1 条边 )

Error ( “生成树不存在” );

}

如何实现“从 E 中取一条权重最小的边 E (v,w) ”---->最小堆

如何判断是否产生回路------>” 并查集”

此算法的时间复杂的为T=O(ELogE),次算法对稀疏图比较友好. 如果改图是稠密图,那么E=v^2

时间复杂度和Prim算法差不多



5 习题

下面通过一道练习题来比较Prim算法和Kruskal算法的优劣

题目的PTA链接

https://pta.patest.cn/pta/test/3512/exam/4/question/85491

题目内容:

5.1题目内容:

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1N编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

代码可以在最后的链接里面



5.2 比较Prim算法和Kruskal算法

上面的习题其实很简单,就是Prim算法和Kruskal算法的应用。很简单,只需要改一下输出即可。

Prim算法在PTA的运行结果:



Kruskal算法在PTA的运行结果:

 

5.2.1空间复杂的比较

从内存的使用情况来看,Prim算法使用的邻接矩阵来存储图,Kruskal算法使用邻接表来存储图,从图中可以看出,邻接矩阵在最N时内存由1M增长到8M,而邻接表的内存始终是在1M。由此可见在同等的数据量的情况下,邻接表比邻接矩阵更加节省内存空间。

5.2.2 时间复杂的比较

就本题的测试结果来看,Kruskal算法的时间复杂度是优于Prim算法的。本题的N最大为1000

M(edge)最大为3N,远远比不上稠密图M=N^2,只能算是稀疏图。所以在稀疏图的情况下,Kruskal算法时间复杂的度较好。和理论的证明一致。

 

 

 

Prim算法求最小生成树的权重和打印路径代码:

  1 /*
  2  * prim.c
  3  *
  4  *  Created on: 2017年5月15日
  5  *      Author: ygh
  6  */
  7 #include <stdio.h>
  8 #include <stdlib.h>
  9 
 10 #define MAX_VERTEX_NUM 100 /*define the max number of the vertex*/
 11 #define INFINITY 65535     /*define double byte no negitive integer max number is 65535*/
 12 #define ERROR -1
 13 
 14 typedef int vertex; /*define the data type of the vertex*/
 15 typedef int weightType; /*define the data type of the weight*/
 16 typedef char dataType; /*define the data type of the vertex value*/
 17 
 18 /*define the data structure of the Edge*/
 19 typedef struct eNode *ptrToENode;
 20 typedef struct eNode {
 21     vertex v1, v2; /*two vertex between the edge <v1,v2>*/
 22     weightType weight; /*the value of the edge\'s weight */
 23 };
 24 typedef ptrToENode edge;
 25 
 26 /*==================A adjacent matrix to describe a graph=========================================*/
 27 
 28 /*define the data structure of the graph*/
 29 typedef struct gMNode *ptrTogMNode;
 30 typedef struct gMNode {
 31     int vertex_number; /*the number of the vertex*/
 32     int edge_nunber; /*the number of the edge*/
 33     weightType g[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; /*define the adjacent matrix weight of graph*/
 34     dataType data[MAX_VERTEX_NUM]; /*define the dataType array to store the value of vertex*/
 35 };
 36 typedef ptrTogMNode adjacentMatrixGraph; /*a graph show by adjacent matrix*/
 37 
 38 /*
 39  create a graph given the vertex number.
 40  @param vertexNum The verter number of the graph
 41  @return a graph with vertex but no any egdgs
 42  */
 43 adjacentMatrixGraph createMGraph(int vertexNum) {
 44     vertex v, w;
 45     adjacentMatrixGraph graph;
 46     graph = (adjacentMatrixGraph) malloc(sizeof(struct gMNode));
 47     graph->vertex_number = vertexNum;
 48     graph->edge_nunber = 0;
 49     /*initialize the adjacent matrix*/
 50     for (v = 0; v < graph->vertex_number; v++) {
 51         for (w = 0; w < graph->vertex_number; w++) {
 52             graph->g[v][w] = INFINITY;
 53         }
 54     }
 55 
 56     return graph;
 57 }
 58 
 59 /*
 60  insert a edge to graph.We will distinct oriented graph and undirected graph
 61  @param graph The graph you want to insert edge
 62  @param e The edge you want to insert the graph
 63  @param isOriented Whether the graph is oriented graph.If the graph is oriented
 64  we will set adjacent matrix [n][m]=[m][n]=edge\'s weight,else we only set
 65  the adjacent matrix [n][m]=edge\'s weight
 66  */
 67 void inserEdgeToMatrix(adjacentMatrixGraph graph, edge e, int isOriented) {
 68     graph->g[e->v1][e->v2] = e->weight;
 69     if (!isOriented) {
 70         graph->g[e->v2][e->v1] = e->weight;
 71     }
 72 }
 73 
 74 /*
 75  construct a graph according user\'s input
 76 
 77  @return a graph has been filled good
 78  */
 79 adjacentMatrixGraph buildMGraph(int isOrdered) {
 80     adjacentMatrixGraph graph;
 81     edge e;
 82     vertex i;
 83     int vertex_num;
 84     scanf("%d", &vertex_num);
 85     graph = createMGraph(vertex_num);
 86     scanf("%d", &(graph->edge_nunber));
 87     if (graph->edge_nunber) {
 88         e = (edge) malloc(sizeof(struct eNode));
 89         for (i = 0; i < graph->edge_nunber; i++) {
 90             scanf("%d %d %d", &e->v1, &e->v2, &e->weight);
 91             e->v1--;
 92             e->v2--;
 93             inserEdgeToMatrix(graph, e, isOrdered);
 94         }
 95     }
 96     return graph;
 97 
 98 }
 99 
100 /*==================A adjacent link to describe a graph=========================================*/
101 /*define the data structure adjacent table node*/
102 typedef struct adjNode *ptrToAdjNode;
103 typedef struct adjNode {
104     vertex adjVerx; /*the index of the vertex*/
105     weightType weight; /*the value of the weight*/
106     ptrToAdjNode next; /*the point to point the next node*/
107 };
108 
109 /*define the data structure of the adjacent head*/
110 typedef struct vNode *ptrToVNode;
111 typedef struct vNode {
112     ptrToAdjNode head; /*the point to point the adjacent table node*/
113     dataType data; /*the space to store the name of the vertex,but some time the vertex has no names*/
114 } adjList[MAX_VERTEX_NUM];
115 
116 /*define the data structure of graph*/
117 typedef struct gLNode *ptrTogLNode;
118 typedef struct gLNode {
119     int vertex_number; /*the number of the vertex*/
120     int edge_nunber; /*the number of the edge*/
121     adjList g; /*adjacent table*/
122 };
123 typedef ptrTogLNode adjacentTableGraph; /*a graph show by adjacent table*/
124 
125 /*
126  create a graph given the vertex number.
127  @param vertexNum The verter number of the graph
128  @return a graph with vertex but no any egdgs
129  */
130 adjacentTableGraph createLGraph(int vertexNum) {
131     adjacentTableGraph graph;
132 
133     vertex v;
134     graph = (adjacentTableGraph) malloc(sizeof(struct gLNode));
135     graph->vertex_number = vertexNum;
136     graph->edge_nunber = 0;
137     /*initialize the adjacent table*/
138     for (v = 0; v < graph->vertex_number; v++) {
139         graph->g[v].head = NULL;
140     }
141     return graph;
142 }
143 
144 /*
145  insert a edge to graph.We will distinct oriented graph and undirected graph
146  The e->v1 and e->v2 are the vertexs\' indexs in the adjacent table
147  @param graph The graph you want to insert edge
148  @param e The edge you want to insert the graph
149  @param isOriented Whether the graph is oriented graph.If the graph is oriented
150  we will set adjacent table graph[v1]->head=v2 and set graph[v1].head=v2
151  otherwise we only set graph[v1].head=v2
152  */
153 void insertEdgeToLink(adjacentTableGraph graph, edge e, int isOriented) {
154     /*build node<v1,v2>*/
155     ptrToAdjNode newNode;
156     newNode = (ptrToAdjNode) malloc(sizeof(struct adjNode));
157     newNode->adjVerx = e->v2;
158     newNode->weight = e->weight;
159     newNode->next = graph->g[e->v1].head;
160     graph->g[e->v1].head = newNode;
161     /*if the graph is directed graph*/
162     if (!isOriented) {
163         newNode = (ptrToAdjNode) malloc(sizeof(struct adjNode));
164         newNode->adjVerx = e->v1;
165         newNode->weight = e->weight;
166         newNode->next = graph->g[e->v2].head;
167         graph->g[e->v2].head = newNode;
168     }
169 }
170 
171 /*
172  build a graph stored by adjacent table
173  */
174 adjacentTableGraph buildLGraph() {
175     adjacentTableGraph graph;
176     edge e;
177     vertex i;
178     int vertex_num;
179 
180     scanf("%d", &vertex_num);
181     graph = createLGraph(vertex_num);
182     scanf("%d", &(graph->edge_nunber));
183     if (graph->edge_nunber) {
184         e = (edge) malloc(sizeof(struct eNode));
185         for (i = 0; i < graph->edge_nunber; i++) {
186             scanf("%d %d %d", &e->v1, &e->v2, &e->weight);
187             insertEdgeToLink(graph, e, 0);
188         }
189     }
190 
191     return graph;
192 }
193 
194 /*
195  * Find the minimal node closest to created tree
196  */
197 vertex findMinDist(adjacentMatrixGraph graph, weightType dist[]) {
198     vertex minV, v;
199     weightType minDist = INFINITY;
200     for (v = 0; v < graph->vertex_number; v++) {
201         if (dist[v] != 0 && dist[v] < minDist) {
202             minDist = dist[v];
203             minV = v;
204         }
205     }
206     if (minDist < INFINITY) {
207         return minV;
208     } else {
209         return ERROR;
210     }
211 }
212 
213 /*
214  * Prim algorithms,we will store the minimal created tree with a adjacent
215  * list table and return the minimal weight
216  * @param mGraph The graph showed by adjacent matrix is to store graph
217  * @param lGraph The graph showed by adjacent list is to store the minimal created tree
218  * @return The weight of the minimal created tree if the graph is connected, otherwise return
219  * <code>ERROR</code>
220  */
221 int prim(adjacentMatrixGraph mGraph, adjacentTableGraph lGraph) {
222 
223     weightType dist[mGraph->vertex_number], totalWeight;
224<

以上是关于最小生成树之Prim算法的主要内容,如果未能解决你的问题,请参考以下文章

最小生成树之Kruskal算法和Prim算法

最小生成树之Prim算法

最小生成树之Prim算法

最小生成树之prim算法

24最小生成树之Prim算法

最小生成树之Prim算法