📅  最后修改于: 2023-12-03 14:45:39.492000             🧑  作者: Mango
Prims 和 Kruskal 算法是两种常用于解决最小生成树问题的算法。它们都是图论中的经典算法,在网络设计、路径规划和数据聚类等领域具有广泛的应用。
本文将分别介绍 Prims 算法和 Kruskal 算法的实现,并使用 C 编程语言提供示例代码。
Prims 算法的实现可以使用最小优先队列(Min-Heap)来选取最小权值边。以下是基于邻接矩阵的 Prims 算法的示例代码:
#include <stdbool.h>
#include <stdio.h>
#include <limits.h>
#define MAX_VERTICES 100
int minKey(int key[], bool mstSet[], int vertices)
{
int min = INT_MAX, min_index;
for (int v = 0; v < vertices; v++)
{
if (!mstSet[v] && key[v] < min)
{
min = key[v];
min_index = v;
}
}
return min_index;
}
void primsMST(int graph[MAX_VERTICES][MAX_VERTICES], int vertices)
{
int parent[MAX_VERTICES];
int key[MAX_VERTICES];
bool mstSet[MAX_VERTICES];
for (int i = 0; i < vertices; i++)
{
key[i] = INT_MAX;
mstSet[i] = false;
}
key[0] = 0;
parent[0] = -1;
for (int count = 0; count < vertices - 1; count++)
{
int u = minKey(key, mstSet, vertices);
mstSet[u] = true;
for (int v = 0; v < vertices; v++)
{
if (graph[u][v] && !mstSet[v] && graph[u][v] < key[v])
{
parent[v] = u;
key[v] = graph[u][v];
}
}
}
printf("Edge \tWeight\n");
for (int i = 1; i < vertices; i++)
{
printf("%d - %d \t%d \n", parent[i], i, graph[i][parent[i]]);
}
}
以上代码中,graph
是输入的图的邻接矩阵表示法,vertices
表示节点的数量。primsMST
函数将根据图 graph
计算并打印出最小生成树的边及其权值。
Kruskal 算法的实现需要使用并查集(Disjoint Set)来判断是否会形成环路。以下是 Kruskal 算法的示例代码:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_EDGES 100
// 边的结构体定义
struct Edge
{
int src, dest, weight;
};
// 图的结构体定义
struct Graph
{
int vertices, edges;
struct Edge* edge;
};
struct Graph* createGraph(int vertices, int edges)
{
struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
graph->vertices = vertices;
graph->edges = edges;
graph->edge = (struct Edge*) malloc(edges * sizeof(struct Edge));
return graph;
}
int find(int parent[], int i)
{
if (parent[i] == -1)
return i;
return find(parent, parent[i]);
}
void Union(int parent[], int x, int y)
{
int xset = find(parent, x);
int yset = find(parent, y);
parent[xset] = yset;
}
int compare(const void* a, const void* b)
{
struct Edge* a1 = (struct Edge*) a;
struct Edge* b1 = (struct Edge*) b;
return a1->weight - b1->weight;
}
void kruskalMST(struct Graph* graph)
{
int vertices = graph->vertices;
struct Edge result[vertices]; // 最小生成树的边
int i = 0; // 循环变量,用于遍历排序后的所有边
int e = 0; // 循环变量,用于遍历结果数组 result[]
qsort(graph->edge, graph->edges, sizeof(graph->edge[0]), compare);
int* parent = (int*) malloc(vertices * sizeof(int));
memset(parent, -1, sizeof(int) * vertices);
while (e < vertices - 1 && i < graph->edges)
{
struct Edge next_edge = graph->edge[i++];
int x = find(parent, next_edge.src);
int y = find(parent, next_edge.dest);
if (x != y)
{
result[e++] = next_edge;
Union(parent, x, y);
}
}
printf("Edge \tWeight\n");
for (i = 0; i < e; i++)
{
printf("%d - %d \t%d \n", result[i].src, result[i].dest, result[i].weight);
}
}
以上代码中,graph
是输入的图的边列表表示法,vertices
表示节点的数量,edges
表示边的数量。kruskalMST
函数将根据图 graph
计算并打印出最小生成树的边及其权值。
你可以根据你的需要,将上述两个算法应用于自己的图数据中。以下是一个简单的使用示例:
#include <stdio.h>
int main()
{
// Prims 算法示例
int graphPrims[MAX_VERTICES][MAX_VERTICES] = {
{0, 2, 0, 6, 0},
{2, 0, 3, 8, 5},
{0, 3, 0, 0, 7},
{6, 8, 0, 0, 9},
{0, 5, 7, 9, 0}
};
printf("Prims 算法\n");
primsMST(graphPrims, MAX_VERTICES);
// Kruskal 算法示例
int vertices = 4;
int edges = 5;
struct Graph* graphKruskal = createGraph(vertices, edges);
graphKruskal->edge[0].src = 0;
graphKruskal->edge[0].dest = 1;
graphKruskal->edge[0].weight = 10;
graphKruskal->edge[1].src = 0;
graphKruskal->edge[1].dest = 2;
graphKruskal->edge[1].weight = 6;
graphKruskal->edge[2].src = 0;
graphKruskal->edge[2].dest = 3;
graphKruskal->edge[2].weight = 5;
graphKruskal->edge[3].src = 1;
graphKruskal->edge[3].dest = 3;
graphKruskal->edge[3].weight = 15;
graphKruskal->edge[4].src = 2;
graphKruskal->edge[4].dest = 3;
graphKruskal->edge[4].weight = 4;
printf("\nKruskal 算法\n");
kruskalMST(graphKruskal);
return 0;
}
请注意,以上示例代码是在静态的图上运行的,你可以根据自己的需求动态创建图并输入相关数据。
Prims 算法和 Kruskal 算法是解决最小生成树问题的两种经典算法。它们在 C 编程语言中的实现可被灵活应用于各种需求场景。最小生成树问题在计算机科学和网络设计中是非常重要的,通过使用这两种算法,可以轻松地找到连接所有节点的最小成本路径。
希望本文能对你理解和实现 Prims 算法和 Kruskal 算法有所帮助!