三十天挑战数据结构(9)最小生成树之普里姆(Prim)算法

咕了无数天之后猛更一波。
其实是因为前两天忙于数据结构结课大作业,正好需要图的各种知识,所以暂时把树这一部分先跳过了。离期末还有一个月的感觉就是,我真的学不完辣!!!
数据结构大作业给我的感觉是盲整邻接表(其实还没太学明白但是硬着头皮写出来了…)然后我明白了之前被它困扰其实不是概念问题,道理大家都懂,只是我的C语言太惨不忍睹了…
经过这么将近十篇博客多多少少还是学懂了一些,弥补了C在指针啊,结构体啊这些地方的缺憾,总之慢慢来吧,鼓励一下自己!

废话不多说了,来分析一下这个最小生成树之普里姆(Prim)算法!
最小生成树其实是为了找遍历一张带权图里所有的结点的最短路径,老实说Prim算法并不好懂,我从《大话数据结构》看到小甲鱼的数据结构教学课程磕磕碰碰总算摸出点门道,帮助理解的话推荐小甲鱼数据结构b站视频的这一章,最后那个动图真的很好理解了,帮助很大!!!

直接用书上的图好了(懒)
在这里插入图片描述
首先,这个算法是利用邻接矩阵来保存图的边信息:
在这里插入图片描述
分段写一下核心算法:

  1. 定义两个数组,作用如注释;初始化数组第一个元素
	int adjvex[MAXVEX];  //定义数组保存顶点下标
    int lowcost[MAXVEX]; //保存相关顶点边权值
    lowcost[0] = 0;      //将v0顶点加入生成树(其实是任意的)
    adjvex[0] = 0;       //初始化第一个顶点下标
  1. 将目前根节点(v0)相关信息存入数组
for (i = 1; i < G->numVertexes; i++)
    {
        lowcost[i] = G->arc[0][i]; //作为初始化,先将v0顶点相关权值存入数组
        adjvex[i] = 0;
    }
  1. for循环,对于图中所有结点进行遍历
for (i = 1; i < G->numVertexes; i++)
    {
        min = INFINITE;
        j = 1;
        k = 0;
        while (j < G->numVertexes) //循环所有顶点
        {
            if (lowcost[j] != 0 && lowcost[j] < min)
            {
                min = lowcost[j];
                k = j;
            }
            j++;
        }
        printf("(%d, %d)", adjvex[k], k);
        lowcost[k] = 0; //把选中的顶点权值设为0,表示已经经过了这个顶点
        //对选中的这个顶点,初始化它的lowcost数组
        for (j = 1; j < G->numVertexes; j++)
        {
            if (lowcost[j] != 0 && G->arc[k][j] < lowcost[j])
            {
                lowcost[j] = G->arc[k][j];
                adjvex[j] = k;
            }
        }
    }

通俗一点理解,可以这样思考:每经过一次遍历后,将已经入树的结点看做一个整体,其它顶点到“这个整体”的最短的路径标记下来,对应顶点进入树,再作为一个整体如此循环直至所有顶点都入树。
最后生成的最小生成树是这样的:
在这里插入图片描述

下面放上全部可运行代码:

#include <stdio.h>
#include <stdlib.h>
#define MAXVEX 9
#define INFINITE 65535

typedef char VertexType;
typedef int EdgeType;
typedef struct
{
    EdgeType arc[MAXVEX][MAXVEX];
    VertexType vexs[MAXVEX];
    int numVertexes, numEdges; //顶点个数,边数目
} MGraph;

//初始化邻接矩阵
void InitialGraph(MGraph *G)
{
    int i, j;
    for (i = 0; i < MAXVEX; i++)
    {
        for (j = 0; j < MAXVEX; j++)
        {
            if (i != j) //初始化时,给所有边赋成极大值
            {
                G->arc[i][j] = INFINITE;
            }
            else //i和j相等时对应权值为0
            {
                G->arc[i][j] = 0;
            }
        }
    }
}

//建立邻接矩阵储存图结构
void CreateGraph(MGraph *G)
{
    int i = 0;
    int x, y, data = 0;
    char c;
    printf("请输入顶点数目:");
    scanf("%d", &G->numVertexes);
    printf("请输入边的数目:");
    scanf("%d", &G->numEdges);
    printf("请依次输入顶点名称:\n");
    getchar();
    while ((c = getchar()) != '\n')
    {
        if (c == ' ')
            continue;
        else
        {
            G->vexs[i] = c;
            i++;
        }
    }
    printf("请依次输入两个顶点下标和之间的权值:\n");
    for (i = 0; i < G->numEdges; i++)
    {
        scanf("%d,%d %d", &x, &y, &data);
        G->arc[x][y] = data;
        G->arc[y][x] = data;
    }
    printf("图建立完毕...\n");
}

//Prim算法生成最小生成树
void MiniSpanTree_Prim(MGraph *G)
{
    int min, i, j, k;
    int adjvex[MAXVEX];  //定义数组保存顶点下标
    int lowcost[MAXVEX]; //保存相关顶点边权值
    lowcost[0] = 0;      //将v0顶点加入生成树(其实是任意的)
    adjvex[0] = 0;       //初始化第一个顶点下标
    for (i = 1; i < G->numVertexes; i++)
    {
        lowcost[i] = G->arc[0][i]; //作为初始化,先将v0顶点相关权值存入数组
        adjvex[i] = 0;
    }

    for (i = 1; i < G->numVertexes; i++)
    {
        min = INFINITE;
        j = 1;
        k = 0;
        while (j < G->numVertexes) //循环所有顶点
        {
            if (lowcost[j] != 0 && lowcost[j] < min)
            {
                min = lowcost[j];
                k = j;
            }
            j++;
        }
        printf("(%d, %d)", adjvex[k], k);
        lowcost[k] = 0; //把选中的顶点权值设为0,表示已经经过了这个顶点
        //对选中的这个顶点,初始化它的lowcost数组
        for (j = 1; j < G->numVertexes; j++)
        {
            if (lowcost[j] != 0 && G->arc[k][j] < lowcost[j])
            {
                lowcost[j] = G->arc[k][j];
                adjvex[j] = k;
            }
        }
    }
}

int main()
{
    MGraph G;
    int i, j;
    InitialGraph(&G);
    CreateGraph(&G);
    for (i = 0; i < MAXVEX; i++)
    {
        for (j = 0; j < MAXVEX; j++)
        {
            printf("%d\t", G.arc[i][j]);
        }
        printf("\n");
    }
    MiniSpanTree_Prim(&G);
    return 0;
}

程序运行结果:

  1. 输入过程
    在这里插入图片描述
  2. 打印邻接矩阵
    在这里插入图片描述
  3. 打印最小生成树的边:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值