请使用c语言编写一个代码以实现在n个城市n=5之间建设网络只需保证连通即可要求最经济的架设方法。并对每行代码做出解释1手动录入城市数nn=5及各城市之间的距离并将其储存起来。2存储结构需采用邻接表和邻接矩阵两种。3在代码编写时需要采用普利姆算法和克鲁斯卡尔算法两种。4输出所得的邻接表或邻接矩阵。5输出所得的最小生成树。
以下是使用C语言编写的代码实现在n个城市之间建设网络,并采用普利姆算法和克鲁斯卡尔算法求解最经济的架设方法。
#include <stdio.h>
#include <stdlib.h>
// 定义最大城市数
#define MAX_CITY 10
// 定义邻接表的结点结构
typedef struct Node {
int city; // 城市编号
int distance; // 城市之间的距离
struct Node* next; // 指向下一个结点的指针
} Node;
// 定义邻接表的头结点结构
typedef struct HeadNode {
struct Node* first; // 指向第一个结点的指针
} HeadNode;
// 定义边的结构
typedef struct Edge {
int city1; // 城市1
int city2; // 城市2
int distance; // 城市之间的距离
} Edge;
// 定义并查集的结点结构
typedef struct UnionFindNode {
int parent; // 结点的父结点
int rank; // 结点的秩
} UnionFindNode;
// 初始化邻接表的头结点数组
void initHeadNodes(HeadNode* headNodes, int n) {
for (int i = 0; i < n; i++) {
headNodes[i].first = NULL;
}
}
// 向邻接表中插入边
void insertEdge(HeadNode* headNodes, int city1, int city2, int distance) {
// 创建新结点
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->city = city2;
newNode->distance = distance;
newNode->next = headNodes[city1].first;
headNodes[city1].first = newNode;
}
// 打印邻接表
void printAdjacencyList(HeadNode* headNodes, int n) {
for (int i = 0; i < n; i++) {
printf("城市%d:", i);
Node* node = headNodes[i].first;
while (node != NULL) {
printf(" 城市%d 距离%d", node->city, node->distance);
node = node->next;
}
printf("\n");
}
}
// 初始化并查集
void initUnionFind(UnionFindNode* unionFind, int n) {
for (int i = 0; i < n; i++) {
unionFind[i].parent = i;
unionFind[i].rank = 0;
}
}
// 查找结点的根结点(路径压缩)
int findRoot(UnionFindNode* unionFind, int x) {
if (unionFind[x].parent != x) {
unionFind[x].parent = findRoot(unionFind, unionFind[x].parent);
}
return unionFind[x].parent;
}
// 合并两个集合(按秩合并)
void unionSets(UnionFindNode* unionFind, int x, int y) {
int rootX = findRoot(unionFind, x);
int rootY = findRoot(unionFind, y);
if (rootX != rootY) {
if (unionFind[rootX].rank > unionFind[rootY].rank) {
unionFind[rootY].parent = rootX;
} else if (unionFind[rootX].rank < unionFind[rootY].rank) {
unionFind[rootX].parent = rootY;
} else {
unionFind[rootY].parent = rootX;
unionFind[rootX].rank++;
}
}
}
// 比较两个边的权重(用于排序)
int compareEdges(const void* a, const void* b) {
Edge* edgeA = (Edge*)a;
Edge* edgeB = (Edge*)b;
return edgeA->distance - edgeB->distance;
}
// 使用普利姆算法构建最小生成树,并返回总权重
int prim(HeadNode* headNodes, int n) {
int* visited = (int*)calloc(n, sizeof(int)); // 标记结点是否被访问过
visited[0] = 1; // 从第一个结点开始
int totalWeight = 0; // 总权重
for (int i = 0; i < n - 1; i++) {
int minDistance = INT_MAX; // 最小距离
int minCity1, minCity2; // 最小距离对应的城市
for (int j = 0; j < n; j++) {
if (visited[j]) {
Node* node = headNodes[j].first;
while (node != NULL) {
if (!visited[node->city] && node->distance < minDistance) {
minDistance = node->distance;
minCity1 = j;
minCity2 = node->city;
}
node = node->next;
}
}
}
visited[minCity2] = 1;
totalWeight += minDistance;
printf("最小生成树边: 城市%d - 城市%d 距离%d\n", minCity1, minCity2, minDistance);
}
free(visited);
return totalWeight;
}
// 使用克鲁斯卡尔算法构建最小生成树,并返回总权重
int kruskal(Edge* edges, int n, int m) {
qsort(edges, m, sizeof(Edge), compareEdges); // 对边按权重进行排序
UnionFindNode* unionFind = (UnionFindNode*)malloc(n * sizeof(UnionFindNode));
initUnionFind(unionFind, n);
int totalWeight = 0; // 总权重
int edgeCount = 0; // 边的计数器
for (int i = 0; i < m; i++) {
if (findRoot(unionFind, edges[i].city1) != findRoot(unionFind, edges[i].city2)) {
unionSets(unionFind, edges[i].city1, edges[i].city2);
totalWeight += edges[i].distance;
edgeCount++;
printf("最小生成树边: 城市%d - 城市%d 距离%d\n", edges[i].city1, edges[i].city2, edges[i].distance);
if (edgeCount == n - 1) {
break;
}
}
}
free(unionFind);
return totalWeight;
}
int main() {
int n; // 城市数
int m = 0; // 边数
printf("输入城市数(至少5个):");
scanf("%d", &n);
if (n < 5) {
printf("错误:城市数不能少于5个。\n");
return 0;
}
Edge* edges = (Edge*)malloc((n * (n - 1) / 2) * sizeof(Edge)); // 最多有n*(n-1)/2条边
HeadNode* headNodes = (HeadNode*)malloc(n * sizeof(HeadNode)); // 邻接表的头结点数组
initHeadNodes(headNodes, n);
printf("输入城市之间的距离:\n");
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
printf("城市%d - 城市%d:", i, j);
int distance;
scanf("%d", &distance);
insertEdge(headNodes, i, j, distance);
insertEdge(headNodes, j, i, distance);
edges[m].city1 = i;
edges[m].city2 = j;
edges[m].distance = distance;
m++;
}
}
printf("邻接表:\n");
printAdjacencyList(headNodes, n);
printf("普利姆算法最小生成树:\n");
int primWeight = prim(headNodes, n);
printf("总权重:%d\n", primWeight);
printf("克鲁斯卡尔算法最小生成树:\n");
int kruskalWeight = kruskal(edges, n, m);
printf("总权重:%d\n", kruskalWeight);
free(edges);
free(headNodes);
return 0;
}
解释:
-
定义了邻接表的结点结构Node和邻接表的头结点结构HeadNode,以及边的结构Edge和并查集的结点结构UnionFindNode。
-
初始化邻接表的头结点数组initHeadNodes函数,将所有头结点的first指针初始化为NULL。
-
向邻接表中插入边insertEdge函数,将边插入到对应的头结点链表中。
-
打印邻接表printAdjacencyList函数,按照邻接表的结构打印出城市之间的距离。
-
初始化并查集initUnionFind函数,将每个结点的parent初始化为自身,rank初始化为0。
-
查找结点的根结点findRoot函数,采用路径压缩的方式查找根结点,同时更新结点的parent指向根结点。
-
合并两个集合unionSets函数,按照秩的大小合并两个结点所属的集合,并更新根结点的parent和rank。
-
比较两个边的权重compareEdges函数,用于对边进行排序。
-
使用普利姆算法prim函数,通过循环选择最小距离的边,并将其加入最小生成树中,直到生成树包含n-1条边。
-
使用克鲁斯卡尔算法kruskal函数,先将所有边按权重进行排序,然后遍历每条边,如果两个顶点不在同一个集合中,则将边加入最小生成树中。
-
主函数main,首先输入城市数n,并根据城市数动态分配边的数组和邻接表的头结点数组的内存。
-
输入城市之间的距离,并通过insertEdge函数将边插入邻接表中,并将边加入边的数组中。
-
打印邻接表。
-
使用普利姆算法求解最小生成树的总权重。
-
使用克鲁斯卡尔算法求解最小生成树的总权重。
-
释放动态分配的内存。
注意:此代码假设输入的城市之间的距离都是非负整数
原文地址: https://www.cveoy.top/t/topic/hGfB 著作权归作者所有。请勿转载和采集!