一、Prim算法和Kruskal算法是什么?
Prim算法:首先把图中所有顶点看作未被访问的点的点集——>随意挑选其中一个点,并把该点放入已被访问过的点的点集——>不断的寻找与被访问点集中的点距离最短的,并且未被访问过的点,加入被访问点集——>当所有点都进入被访问点集,则获得图的最小生成树。
Prim算法查找过程:
Kruskal算法:获得图中所有具有权值的边,从中挑选权值最小的边,若边会与已挑选边形成回路,则该边;不形成回路,则加入最小生成树。
Kruskal算法查找过程:
二、各自的优缺点是什么?
主要差异在于,Prim算法在面对稠密图时效率较高,Kruskal算法在面对稀疏图时效率更高。
三、具体代码
Prim算法:
#include <stdio.h> #include <stdlib.h> #define VISITED 1 #define UNVISITED 0 #define GRAPH_SIZE 6 #define EDGE_MAXLENGTH 32767 typedef struct EdgeCost{ int cost, vex; }; void Prim(int(*graph)[GRAPH_SIZE], EdgeCost *lowcost, int *visited); int main(){ //记录被选出的点到达未被选出点的最小权值边 //如:已选出点:v0,未被选出点:v1,v2,v3,v4,v5,则lowcost[4].cost代表v0到达v4的最小权值,lowcost[4].vex在此表示边的起点是v0 EdgeCost lowcost[GRAPH_SIZE]; //用于标记点是否被访问 int visited[GRAPH_SIZE]; //图 int graph[GRAPH_SIZE][GRAPH_SIZE]; int i, j; //初始化 for (i = 0; i < GRAPH_SIZE; i++){ visited[i] = 0; lowcost[i].cost = EDGE_MAXLENGTH; lowcost[i].vex = -1; } for (i = 0; i < GRAPH_SIZE; i++) for (j = 0; j < GRAPH_SIZE; j++) graph[i][j] = EDGE_MAXLENGTH; graph[0][1] = 7; graph[1][0] = 7; graph[0][2] = 1; graph[2][0] = 1; graph[0][3] = 5; graph[3][0] = 5; graph[2][1] = 5; graph[1][2] = 5; graph[2][3] = 5; graph[3][2] = 5; graph[2][4] = 8; graph[4][2] = 8; graph[2][5] = 4; graph[5][2] = 4; graph[1][4] = 3; graph[4][1] = 3; graph[3][5] = 2; graph[5][3] = 2; graph[4][5] = 6; graph[5][4] = 6; for (i = 0; i < GRAPH_SIZE; i++){ for (j = 0; j < GRAPH_SIZE; j++) printf("%d\t", graph[i][j]); printf("\n"); } printf("\n"); //Prim算法,选择从v0开始 visited[0] = VISITED; for (i = 1; i < GRAPH_SIZE; i++){ if (graph[0][i] != EDGE_MAXLENGTH){ lowcost[i].vex = 0; lowcost[i].cost = graph[0][i]; } } Prim(graph, lowcost, visited); } void Prim(int(*graph)[GRAPH_SIZE], EdgeCost *lowcost, int *visited){ int i, vex, adj, min = EDGE_MAXLENGTH, result = 0; for (i = 0; i < GRAPH_SIZE; i++){ if (visited[i] != VISITED && lowcost[i].cost < min){ adj = i; vex = lowcost[i].vex; min = lowcost[i].cost; }else if (visited[i] == VISITED) result++; } if (result == GRAPH_SIZE) return; visited[adj] = VISITED; printf("( %d, %d) ", vex, adj); for (i = 0; i < GRAPH_SIZE; i++){ if (graph[adj][i] < lowcost[i].cost){ lowcost[i].vex = adj; lowcost[i].cost = graph[adj][i]; } } Prim(graph, lowcost, visited); }
Kruskal算法:
<span style="font-size:12px;">#include <stdio.h> #include <stdlib.h> #define VISITED 1 #define UNVISITED 0 #define MAX_EDGES 20 #define GRAPH_SIZE 6 #define EDGE_MAXLENGTH 32767 typedef struct Edge{ int pre, back, weight; }Edge; int FindRoot(int *root, int point); void Kruscal(Edge *edges, int *root); int main(){ Edge edges[MAX_EDGES]; int root[GRAPH_SIZE]; int graph[GRAPH_SIZE][GRAPH_SIZE]; int i, j, k = 0; //初始化图 for (i = 0; i < GRAPH_SIZE; i++) for (j = 0; j < GRAPH_SIZE; j++) graph[i][j] = EDGE_MAXLENGTH; graph[0][1] = 7; graph[1][0] = 7; graph[0][2] = 1; graph[2][0] = 1; graph[0][3] = 5; graph[3][0] = 5; graph[2][1] = 5; graph[1][2] = 5; graph[2][3] = 5; graph[3][2] = 5; graph[2][4] = 8; graph[4][2] = 8; graph[2][5] = 4; graph[5][2] = 4; graph[1][4] = 3; graph[4][1] = 3; graph[3][5] = 2; graph[5][3] = 2; graph[4][5] = 6; graph[5][4] = 6; //初始化可达的边集 for (i = 0; i < GRAPH_SIZE; i++){ for (j = 0; j < GRAPH_SIZE; j++){ if (graph[i][j] < EDGE_MAXLENGTH){ edges[k].pre = i; edges[k].back = j; edges[k].weight = graph[i][j]; k++; } } } //初始化边的根节点数组 for (i = 0; i < GRAPH_SIZE; i++) root[i] = 0; for (i = 0; i < GRAPH_SIZE; i++){ for (j = 0; j < GRAPH_SIZE; j++) printf("%d\t", graph[i][j]); printf("\n"); } printf("\n"); Kruscal(edges, root); } int FindRoot(int *root, int point){ while (root[point] > 0) point = root[point]; return point; } void Kruscal(Edge *edges, int *root){ int i, j, min, pre, back, visited, weight, buf, edf; for (i = 0; i < MAX_EDGES; i++){ min = EDGE_MAXLENGTH; for (j = 0; j < MAX_EDGES; j++){ if (edges[j].weight < min){ pre = edges[j].pre; back = edges[j].back; min = edges[j].weight; visited = j; } } buf = FindRoot(root, pre); edf = FindRoot(root, back); edges[visited].weight = EDGE_MAXLENGTH; if (buf != edf){ root[buf] = edf; printf("(%d, %d)", pre, back, min); } } }</span>