c语言 最小生成树 包含Kruskal算法代码
时间: 2023-08-31 14:36:41 浏览: 159
### 回答1:
以下是用C语言实现Kruskal算法的代码,该算法可以生成一棵最小生成树:
```
#include <stdio.h>
#include <stdlib.h>
#define MAX_EDGE_NUM 1000
#define MAX_VERTEX_NUM 100
// 定义边的结构体
typedef struct {
int u, v; // 两个顶点
int w; // 权值
} Edge;
// 定义并查集结构体
typedef struct {
int parent[MAX_VERTEX_NUM]; // 每个顶点的父节点
int rank[MAX_VERTEX_NUM]; // 每个顶点的秩
} UnionFindSet;
// 初始化并查集
void makeSet(UnionFindSet* set, int n) {
for (int i = 0; i < n; i++) {
set->parent[i] = i;
set->rank[i] = 0;
}
}
// 查找节点x所在集合的根节点
int find(UnionFindSet* set, int x) {
if (set->parent[x] != x) {
set->parent[x] = find(set, set->parent[x]);
}
return set->parent[x];
}
// 合并两个节点所在的集合
void unionSet(UnionFindSet* set, int x, int y) {
int rootX = find(set, x);
int rootY = find(set, y);
if (rootX != rootY) {
if (set->rank[rootX] > set->rank[rootY]) {
set->parent[rootY] = rootX;
} else if (set->rank[rootX] < set->rank[rootY]) {
set->parent[rootX] = rootY;
} else {
set->parent[rootY] = rootX;
set->rank[rootX]++;
}
}
}
// Kruskal算法
void kruskal(Edge* edges, int n, int m) {
UnionFindSet set;
makeSet(&set, n);
Edge result[MAX_VERTEX_NUM];
int count = 0;
int i = 0;
while (count < n - 1) {
Edge e = edges[i++];
int u = e.u;
int v = e.v;
int w = e.w;
if (find(&set, u) != find(&set, v)) {
result[count++] = e;
unionSet(&set, u, v);
}
}
for (int i = 0; i < count; i++) {
printf("(%d, %d) %d\n", result[i].u, result[i].v, result[i].w);
}
}
// 测试
int main() {
int n, m;
scanf("%d%d", &n, &m);
Edge edges[MAX_EDGE_NUM];
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w);
}
kruskal(edges, n, m);
return 0;
}
```
其中,makeSet函数用于初始化并查集;find函数用于查找节点所在的集合的根节点;unionSet函数用于合并两个节点所在的集合。kruskal函数是Kruskal算法的实现,它先将所有边按权值从
### 回答2:
Kruskal算法是一种用于解决最小生成树问题的经典算法,下面是使用C语言实现Kruskal算法的代码:
```c
#include <stdio.h>
#include <stdlib.h>
// 定义边的结构体
typedef struct {
int source; // 边的起点
int destination; // 边的终点
int weight; // 边的权重
} Edge;
// 定义并查集的结构体
typedef struct {
int *parent; // 每个节点的父节点
int *rank; // 每个节点的秩
} DisjointSet;
// 初始化并查集
void makeSet(DisjointSet *ds, int n) {
ds->parent = (int *)malloc((n+1) * sizeof(int));
ds->rank = (int *)malloc((n+1) * sizeof(int));
for (int i = 1; i <= n; i++) {
ds->parent[i] = i;
ds->rank[i] = 0;
}
}
// 查找节点的根节点
int find(DisjointSet *ds, int x) {
if (ds->parent[x] != x) {
ds->parent[x] = find(ds, ds->parent[x]);
}
return ds->parent[x];
}
// 合并两个集合
void unionSets(DisjointSet *ds, int x, int y) {
int rootX = find(ds, x);
int rootY = find(ds, y);
if (ds->rank[rootX] < ds->rank[rootY]) {
ds->parent[rootX] = rootY;
} else if (ds->rank[rootX] > ds->rank[rootY]) {
ds->parent[rootY] = rootX;
} else {
ds->parent[rootY] = rootX;
ds->rank[rootX]++;
}
}
// Kruskal算法求最小生成树
void kruskal(Edge *edges, int n, int m) {
// 对所有边按权重进行升序排序
for (int i = 0; i < m-1; i++) {
for (int j = 0; j < m-i-1; j++) {
if (edges[j].weight > edges[j+1].weight) {
Edge temp = edges[j];
edges[j] = edges[j+1];
edges[j+1] = temp;
}
}
}
// 初始化并查集
DisjointSet ds;
makeSet(&ds, n);
// 选取边构建最小生成树
int numEdges = 0;
for (int i = 0; i < m; i++) {
int sourceRoot = find(&ds, edges[i].source);
int destinationRoot = find(&ds, edges[i].destination);
if (sourceRoot != destinationRoot) {
printf("选择边 (%d, %d) 权重为 %d\n", edges[i].source, edges[i].destination, edges[i].weight);
unionSets(&ds, sourceRoot, destinationRoot);
numEdges++;
if (numEdges == n-1) {
break;
}
}
}
// 释放内存
free(ds.parent);
free(ds.rank);
}
// 主函数示例
int main() {
// 按照以下结构初始化边的数组
Edge edges[] = {
{1, 2, 4},
{1, 3, 1},
{2, 3, 2},
{2, 4, 1},
{3, 4, 5}
};
int numNodes = 4; // 节点个数
int numEdges = 5; // 边的个数
printf("最小生成树的边为:\n");
kruskal(edges, numNodes, numEdges);
return 0;
}
```
以上是使用C语言实现Kruskal算法的代码,代码中使用了并查集数据结构和排序算法来实现Kruskal算法的核心步骤。该算法通过选择边的方式构建最小生成树,并且保证构成的图是连通的且权重之和最小。
### 回答3:
Kruskal算法是一种常用于求解最小生成树的算法,它的基本思想是:首先对边按照权重从小到大进行排序,然后从权重最小的边开始,依次选择边加入最小生成树的集合中,直到最小生成树包含了所有的顶点。
下面是C语言实现Kruskal算法的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#define MAXV 100 // 最大顶点数
#define MAXE 10000 // 最大边数
typedef struct {
int u, v; // 边的两个顶点
int weight; // 边的权重
} Edge;
typedef struct {
int parent; // 并查集中的父节点
int rank; // 并查集中的秩
} UnionFind;
int cmp(const void *a, const void *b) {
return ((Edge*)a)->weight - ((Edge*)b)->weight;
}
int find(UnionFind* uf, int x) {
if (uf[x].parent != x) {
uf[x].parent = find(uf, uf[x].parent);
}
return uf[x].parent;
}
void merge(UnionFind* uf, int x, int y) {
int rootX = find(uf, x);
int rootY = find(uf, y);
if (rootX != rootY) {
if (uf[rootX].rank < uf[rootY].rank) {
uf[rootX].parent = rootY;
} else if (uf[rootX].rank > uf[rootY].rank) {
uf[rootY].parent = rootX;
} else {
uf[rootY].parent = rootX;
uf[rootX].rank++;
}
}
}
void Kruskal(Edge* edges, int n, int m) {
UnionFind uf[MAXV];
for (int i = 1; i <= n; i++) {
uf[i].parent = i;
uf[i].rank = 0;
}
qsort(edges, m, sizeof(Edge), cmp);
int selected = 0; // 已选取的边数
int index = 0; // 当前考虑的边下标
int cost = 0; // 最小生成树的总权重
while (selected < n - 1 && index < m) {
int u = edges[index].u;
int v = edges[index].v;
if (find(uf, u) != find(uf, v)) { // 判断加入的边是否形成环路
merge(uf, u, v);
printf("选取边: %d-%d, 权重: %d\n", u, v, edges[index].weight);
cost += edges[index].weight;
selected++;
}
index++;
}
printf("最小生成树的总权重为: %d\n", cost);
}
int main() {
int n, m; // 顶点数和边数
scanf("%d %d", &n, &m);
Edge edges[MAXE];
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &edges[i].u, &edges[i].v, &edges[i].weight);
}
Kruskal(edges, n, m);
return 0;
}
```
以上是Kruskal算法的C语言实现示例,通过对边进行排序,并使用并查集数据结构来判断边是否形成环路,从而构建最小生成树。算法的时间复杂度为O(ElogE),E为边数。
阅读全文