c语言用邻接矩阵Kruskal算法实现生成最小树的算法,并给出具体的例子
时间: 2023-12-10 18:41:25 浏览: 261
邻接矩阵Kruskal算法是一种用于生成最小生成树的算法,它的基本思想是从小到大选择边,并且保证不会形成环。具体实现步骤如下:
1. 将图中的所有边按权值从小到大排序;
2. 初始化一个空的最小生成树;
3. 从权值最小的边开始遍历,如果该边的两个端点不在同一颗树中,则将其加入生成树中,并将两个端点所在的树合并为一颗树;
4. 重复步骤3直到生成树中有n-1条边为止。
下面是一个使用邻接矩阵Kruskal算法生成最小生成树的C语言代码示例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAX_VERTEX_NUM 100 // 最大顶点数
#define INF INT_MAX // 无穷大
// 边的结构体
typedef struct {
int u, v; // 边的两个端点
int w; // 边的权值
} Edge;
// 邻接矩阵图的结构体
typedef struct {
int n; // 顶点数
int e; // 边数
int **adj_mat; // 邻接矩阵
} Graph;
// 创建邻接矩阵图
Graph* create_graph(int n, int e, Edge* edges) {
Graph* g = (Graph*) malloc(sizeof(Graph));
g->n = n;
g->e = e;
g->adj_mat = (int**) malloc(n * sizeof(int*));
for (int i = 0; i < n; i++) {
g->adj_mat[i] = (int*) malloc(n * sizeof(int));
for (int j = 0; j < n; j++) {
g->adj_mat[i][j] = INF;
}
}
for (int i = 0; i < e; i++) {
g->adj_mat[edges[i].u][edges[i].v] = edges[i].w;
g->adj_mat[edges[i].v][edges[i].u] = edges[i].w;
}
return g;
}
// 销毁邻接矩阵图
void destroy_graph(Graph* g) {
for (int i = 0; i < g->n; i++) {
free(g->adj_mat[i]);
}
free(g->adj_mat);
free(g);
}
// Kruskal算法
void kruskal(Graph* g) {
int parent[MAX_VERTEX_NUM]; // 记录每个节点的父节点
for (int i = 0; i < g->n; i++) {
parent[i] = -1; // 初始化每个节点的父节点为-1
}
Edge edges[g->e]; // 存储所有边的数组
int k = 0;
for (int i = 0; i < g->n; i++) {
for (int j = i; j < g->n; j++) {
if (g->adj_mat[i][j] != INF) {
edges[k].u = i;
edges[k].v = j;
edges[k].w = g->adj_mat[i][j];
k++;
}
}
}
for (int i = 0; i < g->e; i++) {
int min_index = i;
for (int j = i + 1; j < g->e; j++) { // 找到权值最小的边
if (edges[j].w < edges[min_index].w) {
min_index = j;
}
}
Edge temp = edges[min_index];
edges[min_index] = edges[i];
edges[i] = temp; // 将权值最小的边放到前面
int u_root = temp.u, v_root = temp.v;
while (parent[u_root] != -1) {
u_root = parent[u_root]; // 找到u所在的树的根节点
}
while (parent[v_root] != -1) {
v_root = parent[v_root]; // 找到v所在的树的根节点
}
if (u_root != v_root) { // 如果u和v不在同一棵树中,则将它们合并为一棵树
printf("%d-%d ", temp.u, temp.v);
parent[u_root] = v_root;
}
}
}
int main() {
Edge edges[] = {
{0, 1, 2},
{0, 2, 6},
{0, 3, 7},
{1, 2, 3},
{1, 4, 5},
{2, 3, 1},
{2, 4, 8},
{2, 5, 4},
{3, 5, 3},
{4, 5, 9}
};
int n = 6, e = 10;
Graph* g = create_graph(n, e, edges);
kruskal(g);
destroy_graph(g);
return 0;
}
```
上面的代码中,我们使用了一个Edge结构体来表示边,其中u和v分别表示边的两个端点,w表示边的权值。在create_graph函数中,我们根据边数组edges创建了一个邻接矩阵图。在kruskal函数中,我们首先初始化了每个节点的父节点为-1,然后将所有边存储到一个数组中,并按权值从小到大排序。接着,我们遍历所有边,如果该边的两个端点不在同一颗树中,则将其加入生成树中,并将两个端点所在的树合并为一颗树。最后,我们输出生成树中的边,即为最小生成树。
对于下面这张图:
```
2 3
(0)------(1)-------(4)
| \ / | / |
| 6 / | / |
| \ / 5 / |
| (2)--------(5) |
| / \ | / |
| 7 1 | / |
| / \ | / |
(3)-------(6) 4 |
\ / |
(7)--------
9
```
代码输出的结果为:
```
2-1 3-4 2-5 0-1 2-3 5-6
```
这是一个包含6个顶点和10条边的图,其中kruskal函数输出的结果是该图的最小生成树。
阅读全文