最小生成树算法C语言代码实例

最小生成树算法C语言代码实例

什么是最小生成树?

最小生成树(MST)是指在一张图中,找到一颗包含所有节点的连通子树,且这颗树的边的权值之和最小。其中,连通子树是指子树中任意两点都可以互相到达的树。

Kruskal算法实现最小生成树

Kruskal算法的过程

Kruskal算法是一种贪心算法,它的基本思想是先将图中所有边按权值从小到大排序,然后从小到大地选择边,加入到一个新的集合中,如果加入这个边能够形成一个新的环路,则舍弃这个边,否则就保留这个边,直到加入的边数等于节点数减1为止。此时所构成的边即为最小生成树。

Kruskal算法的代码实现

下面是Kruskal算法的C语言代码实现,其中边的结构体定义如下:

struct Edge {
    int u, v; // 边的两个端点
    int w; // 边的权值
};

核心函数代码:

int cmp(const void* a, const void* b) {
    return ((struct Edge*)a)->w - ((struct Edge*)b)->w;
}

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;
}

void Kruskal(struct Edge edges[], int V, int E) {
    int parent[V];
    memset(parent, -1, sizeof(parent));
    int i = 0, j = 0, k = 0;
    struct Edge result[V];

    // 对所有边按权值从小到大排序
    qsort(edges, E, sizeof(edges[0]), cmp);

    while (j < V - 1 && k < E) {
        int u = edges[k].u;
        int v = edges[k].v;
        int w = edges[k].w;

        int x = find(parent, u);
        int y = find(parent, v);

        if (x != y) {
            result[i++] = edges[k];
            Union(parent, x, y);
            j++;
        }
        k++;
    }

    printf("Edges in MST:\n");
    for (i = 0; i < j; i++) {
        printf("%d - %d : %d\n", result[i].u, result[i].v, result[i].w);
    }
}

Prim算法实现最小生成树

Prim算法的过程

Prim算法也是一种贪心算法,它的基本思想是从某个顶点开始,不断地扩张当前生成树,每次选择当前生成树与其它未加入到生成树中的节点所对应的边中的最短边加入到生成树中,直到所有节点都加入到生成树中为止。此时所构成的边即为最小生成树。

Prim算法的代码实现

下面是Prim算法的C语言代码实现,其中边的结构体定义与之前一致:

struct Edge {
    int u, v; // 边的两个端点
    int w; // 边的权值
};

核心函数代码:

void Prim(int graph[V][V], int V) {
    int parent[V]; // 存放最小生成树的边
    int key[V]; // 存放顶点到最小生成树的最小边权值
    bool mstSet[V]; // 存放那些顶点已经包含在最小生成树中

    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 = minKey(key, mstSet, V);
        mstSet[u] = true;

        for (int v = 0; v < V; v++) {
            if (graph[u][v] && mstSet[v] == false && graph[u][v] < key[v]) {
                parent[v] = u;
                key[v] = graph[u][v];
            }
        }
    }

    printf("Edges in MST:\n");
    for (int i = 1; i < V; i++) {
        printf("%d - %d : %d\n", parent[i], i, graph[i][parent[i]]);
    }
}

示例说明

假设一个图如下所示:

  5  ----- 4
 / \       | \
2   \      |  3
 \   \     | /
  6 - 1 --- 0
      9

按照Kruskal算法,首先将所有边按权值从小到大排序:

(2,6): 3
(0,1): 4
(7,8): 7
(3,4): 8
(6,1): 8
(1,4): 9
(3,5): 10
(1,2): 11

从最小的边开始加入到生成树中,一直到生成树中有5条边为止,这样形成的最小生成树为:

Edges in MST:
2 - 6 : 3
0 - 1 : 4
1 - 4 : 9
6 - 1 : 8

按照Prim算法,首先选择一个顶点,比如顶点0作为根节点,将所有顶点到根节点的最短距离存储在key数组中:

key[] = {0, INF, INF, INF, INF, INF, INF, INF, INF}

然后选择key数组中最短距离的顶点2,将它加入到生成树中,并更新key数组:

key[] = {0, INF, 3, INF, INF, INF, INF, INF, INF}

接下来,选择key数组中最短距离的顶点6,将它加入到生成树中,并更新key数组:

key[] = {0, 6, 3, INF, INF, 10, INF, INF, INF}

重复上述操作,直到生成树中包含所有的顶点,产生的最小生成树为:

Edges in MST:
0 - 1 : 4
1 - 2 : 11
2 - 6 : 3
1 - 4 : 9

总结

以上就是Kruskal算法和Prim算法实现最小生成树的完整攻略。其中,Kruskal算法的时间复杂度为O(ElogE),空间复杂度为O(E),Prim算法的时间复杂度为O(V^2)或O(ElogV),空间复杂度为O(V+E)。在实际使用时,根据图中节点的数量和边的数量来选择恰当的算法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:最小生成树算法C语言代码实例 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • java中的connection reset 异常处理分析

    Java中的Connection reset异常处理分析 异常产生原因 Connection reset异常一般出现在Java程序使用网络连接时,比如Socket连接或HTTP连接等操作。出现这个异常的原因通常是: 网络问题:例如客户端或服务端在网络连接过程中,网络断开或者网络出现故障导致连接异常断开,这时服务器会发送一个RST数据包给客户端,表示物理连接断…

    C 2023年5月23日
    00
  • C语言如何使用函数求素数和举例

    此处我将为您详细讲解关于C语言如何使用函数求素数的完整攻略。整个流程大致分为以下几步: 步骤一:编写函数判断素数 首先,我们需要编写一个函数来判断一个数是否是素数。可以将这个函数定义为:bool isPrime(int n),其中n是待判断的整数,返回值为布尔类型,表示n是否是素数。这个函数的实现过程如下: bool isPrime(int n) { if …

    C 2023年5月23日
    00
  • Win10正式版系统无法开机提示错误代码0xc00000e9的多种解决方法

    以下是“Win10正式版系统无法开机提示错误代码0xc00000e9的多种解决方法”的完整攻略: 问题描述 在启动Win10正式版系统时,可能会遇到提示错误代码0xc00000e9的情况,导致系统无法正常启动。这是一种比较常见的问题,可能会与硬件故障、软件冲突等多种因素有关,接下来我们将介绍多种解决方法。 方法一:检查硬件是否损坏 首先要排除硬件故障造成的可…

    C 2023年5月24日
    00
  • C++ 如何将string转换成全小写

    将string转换成全小写的方法可以使用C++标准库中的algorithm头文件中的transform函数来实现。具体实现流程如下: 包含头文件<algorithm>和<string>。 定义一个string类型的字符串源字符串。 定义一个string类型的字符串目标字符串。 使用transform()函数转换目标字符串。 cpp s…

    C 2023年5月23日
    00
  • Rust使用kind进行异常处理(错误的分类与传递)

    当我们编写代码时,难免会遇到程序中出现错误的情况,比如文件读写失败,网络连接超时等等。Rust中提供了一种异常处理机制,称之为“错误处理(Error Handling)”。在Rust中,我们可以使用kind进行错误分类和传递,下面将详细讲解如何使用kind进行异常处理。 1. 异常处理基础 Rust中,我们通常使用Result类型来进行异常处理。Result…

    C 2023年5月23日
    00
  • win10系统不能更改pin码错误代码0x801c004d怎么办?

    Win10系统无法更改PIN码错误代码0x801c004d解决攻略 如果你在更改Windows 10的PIN码时遇到了错误代码0x801c004d,那么可能是由于某些原因导致了系统无法更改PIN码。下面是解决此问题的完整攻略。 1. 确认你已登录到Microsoft账户 首先,确保你已登录到Microsoft账户。如果你未登录,Windows 10将无法更改…

    C 2023年5月23日
    00
  • 如何使用C++获取指定的重载函数地址

    下面是如何使用C++获取指定的重载函数地址的完整攻略: 1. 使用函数名作为参数获取函数地址 在C++中,对于重载函数,不同重载版本的函数名称可能相同,但是它们的参数类型和参数个数不同。因此,如果我们要获取某个指定重载版本的函数地址,需要使用重载函数的完整名称,包括参数类型和参数个数。例如: void foo(int x); void foo(double …

    C 2023年5月23日
    00
  • Python 字符串处理特殊空格\xc2\xa0\t\n Non-breaking space

    Python 字符串处理中的特殊空格包括非换行空格(Non-breaking space)、制表符(Tab)和换行符(Newline)。在字符串处理中,这些特殊空格可能会对文本处理和分析造成一定的影响。 非换行空格 非换行空格通常是由于文本的格式化处理而产生的,它可以通过 Unicode 编码表中的字符 \xc2\xa0 表示。在 Python 中,可以通过…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部