Prim 普里姆算法(邻接矩阵)C语言版

Prim算法的思维路线较为简单,百度基本都能看懂。但是编程还是有点难的。

整个围绕两个东西转,一个lowcost数组,一个adjvex数组,前者是用来保存当前生成树到其它顶点的权值的。

比如这个图,假设一开始是从0出发,那么首先将0这个点并入到我们的生成树中,顺便设置一遍 lowcost数组,也就是,从0开始到其它顶点的权重。那么,这里有个问题,将0并入到我们的生成树,用什么标记表示这个顶点已经并入到我们的生成树中。这里选择的是用0!!也就是说,一开始,0并入,很好,我将它的lowcost[0]变成0表示这个顶点已经并入到生成树中了。那么我们的生成树到其它顶点的权重是什么呢?到1,是5,到3是无穷(这里的无穷写代码我们可以用一个比较大的数,比如65535),其它类推。那么这个adjvex数组是干嘛的呢?这只是方便我们输出的东西,表示的意思是(假设adjvex[1]是3,就表示当前树到1是通过顶点3的,也就是3->1是选的最小权重的边,如果不懂继续往下看)。

lowcost和adjvex
 0123456
lowcost0511
adjvex0000000

这是我们第一个顶点进入生成树中得到了,我们以这个为初始数据,然后才是真正的开始。

我们选择lowcost中最小的数据,并记录它的下标,比如说叫k。当前最小的是5这个权值,那么对应的下标是1,k=1,代码顶点是1,然后我们需要将这个1并入我们的生成树中,并且谁指向了1?是从0指向了1(0->1),所以,adjvex[1]=0的。同时,因为这个1顶点已经被并入到生成树中了,所以,需要将lowcost[1]=0。得到下表和对应代码

min = 65535;
        j=0;k=0;
        //选出权值最小的
        while (j<G->vexnum){
            if(lowcost[j]!=0&&lowcost[j]<min){
                min = lowcost[j];
                k=j;
            }
            j++;
        }
printf("%d->%d ",adjvex[k],k);
        lowcost[k]=0;//等于0的话代表这个顶点已经加入生成树 下次取权值不会在用到它。

 

 0123456
lowcost0011
adjvex0000000

 

然后 1进入我的生成树,我现在生成树中有{0,1}这两个点。这个新树到其它顶点的权重比老树(只有0这一个点时的树)发生了变化,比如说多了1->4,1->5,1->3,然后判断这些边的权重,是否比我们在lowcost数组中存放的更小,如果是的话就赋值更新。所以我们要更新lowcost数组,因为这个数组代表了当前生成树到其它顶点的权重啊。(比如说下面,我们的生成树到3原来是无穷,现在到3是12,当然小的多,毫不留情将它换成更小的),在转换过程中顺便将adjvex修改,表示是从什么顶点到这条边的。比如,

这里的生成树到3,4,5都是从1到它们的,所以都设置成1,那么你写程序怎么弄出这个1来呢?还记得上面选权值最小时那个小标吗,那个赋值给了k,此时我们只需要将更新过的(更新的条件就是lowcost不是0,不是0代表不在生成树中,而且新树比老树小的值,比如说是G->arc[k][j]<lowcost[j],此时的j是从0开始遍历到6,因为是邻接矩阵方式存储,需要将当前行就是第k行,所有数据和lowcost数组中的元素进行比较,如果lowcost数组中值比较大,就更新lowcost[j]=G->arc[k][j];,然后顺便将adjvex[j]=k;

这行无情的代码就写成了

//更新lowcost数组
        for (j = 0;  j<G->vexnum ; j++) {
            if(lowcost[j]!=0&&G->arc[k][j]<lowcost[j]){
                lowcost[j]=G->arc[k][j];
                adjvex[j]=k;
            }
        }
 0123456
lowcost00111228
adjvex0001110

 

之后,我们选出一个最小的lowcost中的权值,那就是2,对应的下标是4,k=4,此时,然后4这个顶点并入生成树了,所以,将lowcost[4]置为0,表示在生成树中了。

 

 0123456
lowcost00111208
adjvex0001110

 

紧接着,因为4并入生成树,边又发生了改变,多了4->5和4->6,所以更新lowcost数组和adjvex数组。

4->5以前是8,现在一看,咦,顶点5有个权值4比8还小,换掉,成为了4,至于顶点6,呵呵权重,换掉,成为15。

在更新过程中,顺便更新adjvex,上面选最小权重选出来的顶点k=4,写入adjvex中,变成adjvex[5]=k,adjvex[6]=k。

 0123456
lowcost0011120415
adjvex0001144

接着选出权值最小的,,一看就是5这个顶点了,并入生成树(lowcost[5]=0) k=5

 0123456
lowcost0011120015
adjvex0001144

 

接着更新lowcost和adjvex。5->6的权重是3<15,更新lowcost[6]=3。顺便更新adjvex[6]=k=5

 0123456
lowcost001112003
adjvex0001145

 

后面就是一直 选最小,并入生成树(设为0),更新lowcost和adjvex。然后一直到这个几个顶点全部结束,我们是从0开始的,0的权重啥的做为了初值,因此,我们后面只要循环n-1次,这里7个顶点,就是7-1=6是,于是乎,变成了(i = 1; i<G->vexnum ; i++)

来看完整代码

#include <stdio.h>
#include <stdlib.h>
#define MaxVertexNum 7
#define MAX_VALUE 65535
//邻接矩阵
typedef char VertexType;
typedef int EdgeType;
//邻接矩阵
typedef struct MGraph{
    VertexType vex[MaxVertexNum];//顶点数组
    EdgeType arc[MaxVertexNum][MaxVertexNum];//二维边表
    //vexnum代表顶点数目,arcnum代表边数
    int vexnum,arcnum;
}MGraph;

//初始化一个邻接矩阵
MGraph *G = (MGraph *)malloc(sizeof(MGraph));
void initMGraph(MGraph *G){
    G->vexnum=7;
    G->arcnum=11;
    for (int i = 0; i <7 ; ++i) {
        G->vex[i]=i;
    }
    int arr[MaxVertexNum][MaxVertexNum] ={
            {0,5,11,MAX_VALUE,MAX_VALUE,MAX_VALUE,MAX_VALUE},
            {5,0,MAX_VALUE,12,2,8,MAX_VALUE},
            {11,MAX_VALUE,0,24,MAX_VALUE,MAX_VALUE,20},
            {MAX_VALUE,12,24,0,MAX_VALUE,MAX_VALUE,18},
            {MAX_VALUE,2,MAX_VALUE,MAX_VALUE,0,4,15},
            {MAX_VALUE,8,MAX_VALUE,MAX_VALUE,4,0,3},
            {MAX_VALUE,MAX_VALUE,20,18,15,3,0}
    };

    for (int i = 0; i <MaxVertexNum ; ++i) {
        for (int j = 0; j <MaxVertexNum ; ++j) {
            G->arc[i][j]=arr[i][j];
        }
    }
}



//prim算法 王道版

void PRIM(MGraph *G){
    int min,i,j,k;
    int lowcost[MaxVertexNum];
    int adjvex[MaxVertexNum];
    lowcost[0]=0;
    adjvex[0]=0;
    for (i = 1; i < G->vexnum; ++i) {
        lowcost[i]=G->arc[0][i];
        adjvex[i]=0;
    }

    for (i = 1;  i<G->vexnum ; i++) {
        min = 65535;
        j=0;k=0;
        //选出权值最小的
        while (j<G->vexnum){
            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 = 0;  j<G->vexnum ; j++) {
            if(lowcost[j]!=0&&G->arc[k][j]<lowcost[j]){
                lowcost[j]=G->arc[k][j];
                adjvex[j]=k;
            }
        }
    }
}

int main(){
    initMGraph(G);
    PRIM(G);
}

 

  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值