最小生成树---普里姆算法

【普里姆算法】
本算法以无向图为例,图的存储方式采用邻接矩阵
1)以第一个顶点开始本算法,将第一个顶点(i = 0)加入最小生成树集low_cost[i] = 0,0代表已经加入生成树集;
2)遍历第i行邻接矩阵,更新与顶点i有边的顶点的权值(该权值集的初始化值为与第一个顶点有边连接的顶点的权值)
3)遍历这个low_cost权值集合,找到最小权值并输出

为了找到与当前顶点有边的前一个顶点,算法用Vertex_Information[]进行了记录


我们先为左图构造邻接矩阵,如右图所示


算法从A点开始生成最小生成树,代码如下:

/*********************************************************************
Author:tmw
date:2017-10-17
********************************************************************************************/
#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTEX 100
#define inf 65535  //用65535代表无穷大
/*************************建立无向图邻接矩阵**************************/
typedef struct Matrix_Graph
{
    char vertex[MAX_VERTEX];//存储顶点信息
    int edge[MAX_VERTEX][MAX_VERTEX];//存储边信息
    int vertex_number,edge_number;//存储图中的顶点数和边数
}Matrix_Graph;
void create_non_direction_matrix_Graph( Matrix_Graph *G )
{
    int i,j,w,k;
    printf("请输入顶点数和边数:\n");
    scanf("%d %d",&G->vertex_number,&G->edge_number);

    printf("请输入无向图顶点信息(如ABCD...):\n");
    char ch;
    while( ( ch = getchar() ) != '\n' );
    for( i = 0 ; i < G->vertex_number ; i++ )
        scanf("%c",&G->vertex[i]);

    //初始化边信息
    for( i = 0 ; i < G->vertex_number ; i++ )
        for( j = 0 ; j < G->vertex_number ; j++ )
        {
            if( i == j )
                G->edge[i][j] = 0;
            else
                G->edge[i][j] = inf;
        }

    printf("请输入无向图中相连的两个顶点下标值(Vi,Vj),以及权值---即边信息\n");
    for( k = 0 ; k < G->edge_number ; k++ )
    {
        scanf("%d %d %d",&i,&j,&w);
        G->edge[i][j] = w;
        G->edge[j][i] = G->edge[i][j];//由于是无向图,故是对称阵
    }
    //打印邻接矩阵
    for( i = 0 ; i < G->vertex_number ; i++ )
    {
        for( j = 0 ; j < G->vertex_number ; j++ )
            printf("%d\t",G->edge[i][j]);
        printf("\n");
    }
}
void Min_Create_Tree_Prim( Matrix_Graph *G )
{
    int i,j,min;
    int mark = 0;
    int low_cost[MAX_VERTEX];
    int Vertex_Information[MAX_VERTEX];//便于找到权值最小边的前一个顶点

    low_cost[0] = 0;     //low_cost记录已经用于生成最小生成树的顶点,若为0,则标记为用过
                        //这里从第一个顶点开始生成最小生成树,因此首先标记它为0
    for( i = 1 ; i < G->vertex_number ; i++ )//因为第一个顶点已经纳入生成树,因此从第二个顶点开始遍历
    {
        low_cost[i] = G->edge[0][i];//将与第一个顶点有边相连的顶点权值放入low_cost数组
        Vertex_Information[i] = 0; //初始化相关顶点的下标都从第一个顶点开始
    }
    for( i = 1 ; i < G->vertex_number ; i++ )
    {
        min = inf;
        j = 1;
        while( j < G->vertex_number )//找出与当前顶点权值最小的顶点
        {
            if( low_cost[j]!=0 && low_cost[j] < min )
            {
                min = low_cost[j];
                mark = j;//将最小权值顶点做个标记
            }
            j++;
        }
        low_cost[mark] = 0;//标记新加入顶点已经被加入生成树
        printf("[%d %d] ---",Vertex_Information[mark],mark);//打印顶点下标号
        printf("%c %c\n",G->vertex[Vertex_Information[mark]],G->vertex[mark]);//打印找到的当前顶点的最小权值边

        //找 与当前顶点和新加入顶点中 还相连的其他顶点
        for( j = 1 ; j < G->vertex_number ; j++ )
        {
            if( low_cost[j] != 0 && low_cost[j] > G->edge[mark][j] )//更新 与当前顶点和新加入顶点间 其他与之相连顶点的权值
            {
                low_cost[j] = G->edge[mark][j];
                Vertex_Information[j] = mark;//标记边的第一个顶点
            }
        }
    }
}
int main()
{
    Matrix_Graph *G;
    G = (Matrix_Graph*)malloc(sizeof(Matrix_Graph));
    create_non_direction_matrix_Graph(G);
    Min_Create_Tree_Prim(G);
    return 0;
}

【程序执行结果】


从代码结果可看出,本次构造的最小生成树路径为:[A B]、[A F]、[B I]、[I C]、[B G]、[G H]、[H E]、[H D]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值