频道文章 行业资讯 c语言最小生成树的实现

c语言最小生成树的实现

4
 

C语言最小生成树的实现

最小生成树(Minimum Spanning Tree,简称MST)是图论中一个重要的概念,它在许多应用中都有广泛的应用,比如网络设计、通信网络、电力传输等领域。在C语言中,我们可以通过多种算法来实现最小生成树,其中包括Prim算法和Kruskal算法。本文将介绍这两种算法在C语言中的实现,帮助您深入了解最小生成树的原理和实现过程。

1. Prim算法

Prim算法是一种贪心算法,它从图中的一个顶点出发,逐步扩展生成最小生成树。以下是Prim算法的基本思想和实现步骤:

1.1 基本思想

  1. 从任意顶点开始,将其加入最小生成树中。
  2. 重复以下步骤,直到所有顶点都被加入最小生成树: a. 找到最小生成树中与当前树相连的顶点中,与其他顶点之间边权重最小的顶点。 b. 将该顶点加入最小生成树中。

1.2 C语言实现

#include <stdio.h>
#include <stdbool.h>

#define V 5 // 图中顶点的数量

// 寻找最小生成树中与当前树相连的顶点中,与其他顶点之间边权重最小的顶点
int findMinKey(int key[], bool mstSet[]) {
    int min = INT_MAX, min_index;

    for (int v = 0; v < V; v++) {
        if (!mstSet[v] && key[v] < min) {
            min = key[v];
            min_index = v;
        }
    }

    return min_index;
}

// 打印最小生成树
void printMST(int parent[], int graph[V][V]) {
    printf("Edge \tWeight\n");
    for (int i = 1; i < V; i++) {
        printf("%d - %d \t%d \n", parent[i], i, graph[i][parent[i]]);
    }
}

// Prim算法实现
void primMST(int graph[V][V]) {
    int parent[V]; // 用于存储最小生成树中每个顶点的父节点
    int key[V];    // 用于存储顶点与最小生成树之间的边权重
    bool mstSet[V]; // 用于标记顶点是否已加入最小生成树

    // 初始化key和mstSet数组
    for (int i = 0; i < V; i++) {
        key[i] = INT_MAX;
        mstSet[i] = false;
    }

    key[0] = 0; // 从第一个顶点开始生成最小生成树
    parent[0] = -1; // 第一个顶点作为根节点

    for (int count = 0; count < V - 1; count++) {
        int u = findMinKey(key, mstSet); // 找到与当前树相连的顶点中,与其他顶点之间边权重最小的顶点
        mstSet[u] = true; // 将该顶点加入最小生成树

        // 更新与u相邻的顶点的key值和parent数组
        for (int v = 0; v < V; v++) {
            if (graph[u][v] && !mstSet[v] && graph[u][v] < key[v]) {
                parent[v] = u;
                key[v] = graph[u][v];
            }
        }
    }

    printMST(parent, graph); // 打印最小生成树
}

int main() {
    int graph[V][V] = {
        {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}
    };

    primMST(graph); // 调用Prim算法生成最小生成树

    return 0;
}

2. Kruskal算法

Kruskal算法是一种基于边的贪心算法,它按照边的权重递增顺序选择边,并确保选择的边不会形成回路,直到生成最小生成树为止。以下是Kruskal算法的基本思想和实现步骤:

2.1 基本思想

  1. 将图中的所有边按权重从小到大排序。
  2. 从权重最小的边开始遍历,如果该边的两个顶点不在同一连通分量中,则将其加入最小生成树中,并合并这两个连通分量。
  3. 重复以上步骤,直到最小生成树中的边数等于顶点数减1。

2.2 C语言实现

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

#define V 5 // 图中顶点的数量
#define E 7 // 图中边的数量

// 边的结构体
struct Edge {
    int src, dest, weight;
};

// 图的结构体
struct Graph {
    int V, E;
    struct Edge* edges;
};

// 创建图
struct Graph* createGraph(int V, int E) {
    struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph));
    graph->V = V;
    graph->E = E;
    graph->edges = (struct Edge*)malloc(E * 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* edge1 = (struct Edge*)a;
    struct Edge* edge2 = (struct Edge*)b;
    return edge1->weight - edge2->weight;
}

// 打印最小生成树
void printMST(struct Edge result[], int e) {
    printf("Edge \tWeight\n");
    for (int i = 0; i < e; i++) {
        printf("%d - %d \t%d \n", result[i].src, result[i].dest, result[i].weight);
    }
}

// Kruskal算法实现
void kruskalMST(struct Graph* graph) {
    int parent[V];
    struct Edge result[V];
    int e = 0;
    int i = 0;

    // 初始化parent数组,每个顶点都是一个独立的连通分量
    for (int v = 0; v < V; v++) {
        parent[v] = -1;
    }

    // 将图的所有边按权重排序
    qsort(graph->edges, graph->E, sizeof(graph->edges[0]), compare);

    // 选择权重最小的边,如果两个顶点不在同一个连通分量中,则将边加入最小生成树
    while (e < V - 1 && i < graph->E) {
        struct Edge next_edge = graph->edges[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);
        }
    }

    printMST(result, e); // 打印最小生成树
}

int main() {
    struct Graph* graph = createGraph(V, E);
    graph->edges[0].src = 0;
    graph->edges[0].dest = 1;
    graph->edges[0].weight = 2;
    graph->edges[1].src = 0;
    graph->edges[1].dest = 3;
    graph->edges[1].weight = 6;
    graph->edges[2].src = 1;
    graph->edges[2].dest = 2;
    graph->edges[2].weight = 3;
    graph->edges[3].src = 1;
    graph->edges[3].dest = 4;
    graph->edges[3].weight = 5;
    graph->edges[4].src = 2;
    graph->edges[4].dest = 4;
    graph->edges[4].weight = 7;
    graph->edges[5].src = 3;
    graph->edges[5].dest = 4;
    graph->edges[5].weight = 9;
    graph->edges[6].src = 3;
    graph->edges[6].dest = 1;
    graph->edges[6].weight = 8;

    kruskalMST(graph); // 调用Kruskal算法生成最小生成树

    return 0;
}

3. 总结

最小生成树是图论中的一个重要概念,它在实际应用中有广泛的应用价值。本文介绍了Prim算法和Kruskal算法在C语言中的实现过程。通过理解这两种算法的原理和代码实现,我们可以更好地应用最小生成树算法解决实际问题,在网络设计、通信网络、电力传输等领域取得更优的成果。

在实际应用中,根据问题的具体特点和需求选择合适的算法是至关重要的。同时,我们也可以根据实际情况优化算法,提高算法的执行效率和数据处理能力。希望本文能为您在C语言中实现最小生成树提供一定的帮助,祝您在图论算法的学习和应用中取得更多的成功!

更新:2026-02-18 00:00:16 © 著作权归作者所有
下一篇
没有了
QQ
微信
客服