C语言普里姆算法最小生成树

目录

1.生成树的概念

2.普里姆算法最小生成树(Prim)

3.源代码示例

3.1Prim算法


1.生成树的概念

(1)子图包含原图全部节点,子图为连通图

(2)在(1)的前提下使子图尽可能的少包含原图中的边

满足以上两点的子图称为原图的生成树。生成树必定包含且仅包含原图的 n - 1 条边

最小生成树:在图的所有生成树中,n - 1 条边上权值和最小的树

2.普里姆算法最小生成树(Prim)

G = (V, E)为一连通网。V:网中所有点的集合;E:网中所有带权边的集合

设两个新的集合U,T:

(1)U:存放G的最小生成树的节点

(2)T:存放G的最小生成树的边

Prim算法构造最小生成树步骤:

(1)令集合U的初值为 U = { U1 }(假设构造最小生成树从U1出发)

(2)令集合T的初值为 T = { }

(3)从所有 u \epsilon U,v \epsilon V - U的边中选择具有最小权值的边(u,v),将节点 v 加入 U,边(u,v)加入 T

(4)不断重复步骤(3),直至 U = V 时最小生成树构造完毕。

以上图为例:

3.源代码示例

3.1Prim算法

实现此算法需要设置两个辅助数组:lowcost、colsevertex

(1)lowcost:保存集合 V - U 中各节点与集合 U 中各节点构成的边中具有最小权值的边的权值。若lowcost [ i ]  = 0,表明下标 为 i 的节点已加入集合 U 中

(2)closevertex:保存依附于最小权值边的在集合 U 中的节点

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

#define INFINITY 10000      /* 假定边上权值无穷大时为10000 */
#define MAX_VERTEX_NUM 100  /* 图中最大节点数 */
typedef char VertexType;    /* 顶点类型设置为字符型 */
typedef int EdgeType;       /* 边上权值类型设置为整型 */
typedef struct              /* 边表节点 */
{
    VertexType vex[MAX_VERTEX_NUM];                 /* 图中节点 */
    EdgeType edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; /* 邻接矩阵 */
    int vexnum;                                     /* 节点的数目 */
    int edgenum;                                    /* 边的数目 */
}MGraph;
 
void CreateMG(MGraph * MG);         /* 邻接矩阵法创建无向图 */
void PrintMG(MGraph MG);            /* 邻接矩阵形式输出图MG */
void MiniSpanTree_Prim(MGraph MG);  /* Prim算法建立最小生成树 */
void locateVex(MGraph MG, VertexType vex, int * index);
                                    /* 定位节点vex的下标并赋给index */
                             
int main(void)
{
    MGraph g;
 
    CreateMG(&g);
    printf("------------------------------\n");
    printf("vexnum = %d ; edgenum = %d\n", g.vexnum, g.edgenum);
    printf("------------------------------\n");
    PrintMG(g);
    printf("------------------------------\n");
    MiniSpanTree_Prim(g);

    return 0;
}
void CreateMG(MGraph * MG)
{
    int i = 0, j, k, w;                 /* w:权值 */
    char ch;
 
    printf("请依次输入顶点数、边数:");
    scanf("%d %d", &(MG->vexnum), &(MG->edgenum));
 
    printf("请依次输入顶点(以回车结束输入):");
    getchar();
    while ((ch = getchar()) != '\n')    /* 输入顶点信息 */
        MG->vex[i++] = ch;
 
    for (i = 0; i < MG->vexnum; i++)    /* 初始化邻接矩阵 */
        for (j = 0; j < MG->vexnum; j++)
            MG->edges[i][j] = INFINITY;
 
    printf("顶点 | 下标\n");
    for (i = 0; i < MG->vexnum; i++)    /* 显示图中顶点及其对应下标 */
    {
        printf("%3c%6d\n", MG->vex[i], i);
    }
 
    printf("请输入每条边对应的两个顶点下标及边的权值(格式:i j w):\n");
    for (k = 0; k < MG->edgenum; k++)   /* 建立邻接矩阵 */
    {
        scanf("\n%d%d%d", &i, &j, &w);  /* 输入边的两个节点及权值 */
        MG->edges[i][j] = w;            /* 将矩阵对应位置元素置为权值 */
        MG->edges[j][i] = w;
    }
}
void PrintMG(MGraph MG)
{
    int i, j;
 
    for (i = 0; i < MG.vexnum; i++)         /* 输出邻接矩阵 */
    {
        for (j = 0; j < MG.vexnum; j++)
        {
            if (MG.edges[i][j] == INFINITY) /* 节点不连通时,输出'#'代表无穷大 */
                printf("%3c", '#');
            else                            /* 节点连通时,输出边上权值 */
                printf("%3d", MG.edges[i][j]);
        }
        printf("\n");
    }
}
void MiniSpanTree_Prim(MGraph MG)
{
    int i, j, k, index, mincost;        /* index:开始节点下标 */
    int lowcost[MG.vexnum], closevertex[MG.vexnum];
    char ch;                            /* 最小生成树的开始节点 */

    printf("请输入开始节点:");
    getchar();
    scanf("%c", &ch);
    locateVex(MG, ch, &index);          /* 求出开始节点的下标并赋给index */

    lowcost[index] = 0;
    closevertex[0] = index;             /* 将开始节点加入集合U */
    for (i = 0; i < MG.vexnum; i++)     /* 辅助数组初始化 */
        if (i != index) 
            lowcost[i] = MG.edges[index][i];
    
    for (i = 1; i < MG.vexnum; i++)
    {
        mincost = INFINITY;
        for (j = 0; j < MG.vexnum; j++)
        {
            if (lowcost[j] < mincost && lowcost[j] != 0)
            {
                mincost = lowcost[j];   /* 最小权值 */
                k = j;                  /* 权值最小的节点下标 */
            }
        } 
                                        /* 输出当前顶点边中权值最小的边 */
        printf("顶点:%c ;权值:%d\n", MG.vex[k], mincost);
        lowcost[k] = 0;                 /* 将当前顶点的权值设为0,表示此顶点已经完成任务 */
        closevertex[i] = k;             /* 与权值最小边关联的节点下标并入集合U */

        for (j = 0; j < MG.vexnum; j++) /* 更新节点与其他节点之间的最小权值和集合U */
        {
            if (MG.edges[k][j] < lowcost[j])
                lowcost[j] = MG.edges[k][j];
        }
    } 
} 
void locateVex(MGraph MG, VertexType vex, int * index)
{
    int i;

    for (i = 0; i < MG.vexnum; i++)
    {
        if (MG.vex[i] == vex)
        {
            *index = i;
            return;
        }
    }
    printf("节点定位失败!\n");
}

发布了50 篇原创文章 · 获赞 38 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42250302/article/details/89553811
今日推荐