图的数组表示法(邻接矩阵)与Prim算法

普里姆(Prim)算法与最小生成树
最小生成树(MST)

对于连通网(带权图),选择生成树的总代价最少(Minimum Spanning Tree,MST ),比如一个N个城市之间的通信网,网的顶点代表城市,边代表这条路的修路费。那么这样就设计一个最小花费的问题。

最小生成树可以由普里姆(Prim)算法和Kruskal(克鲁斯卡尔)算法求出
一:普里姆(Prim)算法

1:需要邻接矩阵作为图的存储结构
2:需要一个辅助数组来记录从U到V-U的最小代价closedge[i]
3:这个U刚开始时候为空,逐个一个一个添加进U里

(1):图的邻接矩阵
1:用两个数组分别表示(顶点)、(边或弧)

注意事项:用65535来代表无穷大,表示两个顶点没有联系
存储结构:

#define INT_MAX        65535                                        //最大值65535,表示两顶点没有联系
#define MAX_VERTEX_NUM 20                                           //最多顶点数

typedef char VertexType;
typedef int  EdgeType;

//有向图, 有向网, 无向图, 无向网
enum GraphKind {
    DG, DN, UDG, UDN
};

//顶点信息
typedef struct ArcCell {
    EdgeType wight;

}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];                //二维数组  

//弧的信息
typedef struct MGraph {
    VertexType vexs[MAX_VERTEX_NUM];                                //顶点向量  
    AdjMatrix  arcs;                                                //邻接矩阵  
    int vexnum, arcnum;                                             //图的当前顶点数和弧数  
    GraphKind   kind;                                               //图的种类标志  
}MGraph;
2:建立无向图的邻接矩阵

代码逻辑:
(1)输入所有顶点
(2)输入所有的边
(3)将所有的边都设置成65535,表示图现在是孤立点,还没有相互联系
(4)获取输入弧的两个顶点在顶点数组(邻接矩阵的两个数组–顶点数组,弧(边)数组)的位置
(5)由于是无向图,且没有使用矩阵的压缩储存,所以这里对称赋值
G.arcs[i][j].wight = G.arcs[j][i].wight = w;
注意事项:
这里scanf的%c输入是比较特殊的:
(1):需要用getchar()读走空格
(2):scanf(” %c”, &G.vexs[i]); 添加一个空格(%c前有一个空格),读走回车
这里不详细讲了,具体在下面链接博客(还不清楚,可以去看看):
https://blog.csdn.net/weixin_39956356/article/details/80371735
相关代码:

//建立无向图的邻接矩阵  
void CreatMGraph(MGraph &G)
{
    for (int i = 0; i < G.vexnum; i++) {
        printf("Please enter %d data:", i + 1);
        scanf(" %c", &G.vexs[i]);                                           //输入顶点值
    }
    for (int i = 0; i<G.vexnum; i++)
        for (int j = 0; j<G.vexnum; j++)
            G.arcs[i][j].wight = INT_MAX;           //邻接矩阵初始化  

    VertexType v1, v2;
    EdgeType w;
    int i, j;
    printf("Please input the two data of arc and wight,for example: A C 5\n");
    for (int k = 0; k < G.arcnum; k++) {
        printf("The %d arc: ", k + 1);
        scanf(" %c", &v1);                                                      //输入第一个顶点
        getchar();                                                              //把输入的空格读走
        v2 = getchar();                                                         //输入弧的第二个顶点
        scanf("%d", &w);                                                        //输入结点数,弧数
        i = LocateVex(G, v1);                                                   //获取弧的第一个节点位置
        j = LocateVex(G, v2);                                                   //获取弧的第二个节点位置

        G.arcs[i][j].wight = G.arcs[j][i].wight = w;                            //把权值存放在邻接矩阵中
    }
}
(2):Prim算法描述

代码逻辑:
(1)辅助数组初始化,把第一个点的邻接矩阵拷贝到辅助数组,将第一个顶点并入U集
辅助数组结构:

//Prim算法中的辅助信息
struct prim{
    VertexType adjvex;                                              //存放最短路径的出发节点结点
    EdgeType   lowcost;                                             //最短路径
};

struct prim closedge[MAX_VERTEX_NUM];

(2)选择其余G.vexnum - 1个顶点,并选择最小代价的边
(3)输出路径与权值,将mincost并入U集
(4)如果有更小的边,把小的替换原来的
选取书上的例子,最小树创建过程:
这里写图片描述
辅助数组及变化:
这里写图片描述
最短路径及权值:
这里写图片描述

普里姆算法:

/************************************************************************
**                      普里姆算法
**  输入参数:MGraph &G          图(邻接矩阵表示)
            :VertexType u       任选一个顶点
**  返回参数:minSum         最短路径之和
*************************************************************************/

int MiniSpanTree_Prim(MGraph &G, VertexType u)
{
    int k = LocateVex(G, u);                                                                            //确定第一个顶点的位置
    closedge[k].lowcost = 0;                                                                            //并入U集
    for (int i = 0; i < G.vexnum; i++)                                                                  //初始化辅助数组
        if(i != k)
        { 
            closedge[i].adjvex = u;                                                                     //存入起始结点
            closedge[i].lowcost = G.arcs[k][i].wight;                                                   //邻接矩阵该行拷贝到辅助数组中
        }

    int minSum = 0;                                                                                     //最短路径之和
    for (int i = 0; i < G.vexnum - 1; i++)                                                              //选择其余G.vexnum - 1个顶点
    {
        int mincost = minArc(G, closedge);                                                              //选择最小代价的边
        printf("%c--%c  %d\n", closedge[mincost].adjvex, G.vexs[mincost], closedge[mincost].lowcost);   //输出路径与权值
        minSum += closedge[mincost].lowcost;                                                            //最短路径之和
        closedge[mincost].lowcost = 0;                                                                  //将mincost并入U集
        for (int j = 0; j < G.vexnum; j++)                                                              
        {
            if (G.arcs[mincost][j].wight < closedge[j].lowcost)                                         //如果有更小的边,把小的替换原来的
            {
                closedge[j].adjvex = G.vexs[mincost];
                closedge[j].lowcost = G.arcs[mincost][j].wight;
            }
        }
    }
    return minSum;                                                                                      //返回最短路径之和
}
(3):主函数
#include "stdafx.h"
#include "Prim.h"


int main()
{
    MGraph G;
    printf("Please enter vexnum and arcnum: ");
    scanf("%d %d", &G.vexnum, &G.arcnum);                                               //输入结点数,弧数

    CreatMGraph(G);                                                                     //建立无向图的邻接矩阵 
    printf("\nTne output of Adjacency Matrix:\n\n");
    printMatrixGraph(G);                                                                //输出邻接矩阵
    printf("\nTne shortest path of Graph:\n\n");
    printf("\nThe sum of the shortest paths is %d.\n", MiniSpanTree_Prim(G, G.vexs[0]));//输出路径与权值

    return 0;
}
(4):代码输出

这里写图片描述

感谢与源代码
1:感谢一下博主文章对我的帮助:
https://blog.csdn.net/zguiz/article/details/54633115
2:源代码(VS2017)(这里说一下:VS工程有个.vs的隐藏配置文件,如果第一次弹出配置选错了,直接删除.vs,第二次打开会再次提示。VS向下兼容)
链接: https://pan.baidu.com/s/1Wv8uqTW7dU6mzinZSNCUgw 密码: p8nb

  • 10
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值