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

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

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

723ea354adf0f0dd11667762d5825f46.png

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

lowcost和adjvex

0

1

2

3

4

5

6

lowcost

0

5

11

adjvex

0

0

0

0

0

0

0

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

我们选择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 (jvexnum){

if(lowcost[j]!=0&&lowcost[j]

min = lowcost[j];

k=j;

}

j++;

}

printf("%d->%d ",adjvex[k],k);

lowcost[k]=0;//等于0的话代表这个顶点已经加入生成树 下次取权值不会在用到它。

0

1

2

3

4

5

6

lowcost

0

0

11

adjvex

0

0

0

0

0

0

0

然后 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]arc[k][j];,然后顺便将adjvex[j]=k;

这行无情的代码就写成了

//更新lowcost数组

for (j = 0; jvexnum ; j++) {

if(lowcost[j]!=0&&G->arc[k][j]

lowcost[j]=G->arc[k][j];

adjvex[j]=k;

}

}

0

1

2

3

4

5

6

lowcost

0

0

11

12

2

8

adjvex

0

0

0

1

1

1

0

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

0

1

2

3

4

5

6

lowcost

0

0

11

12

0

8

adjvex

0

0

0

1

1

1

0

紧接着,因为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。

0

1

2

3

4

5

6

lowcost

0

0

11

12

0

4

15

adjvex

0

0

0

1

1

4

4

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

0

1

2

3

4

5

6

lowcost

0

0

11

12

0

0

15

adjvex

0

0

0

1

1

4

4

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

0

1

2

3

4

5

6

lowcost

0

0

11

12

0

0

3

adjvex

0

0

0

1

1

4

5

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

来看完整代码

#include

#include

#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

for (int j = 0; 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; ivexnum ; i++) {

min = 65535;

j=0;k=0;

//选出权值最小的

while (jvexnum){

if(lowcost[j]!=0&&lowcost[j]

min = lowcost[j];

k=j;

}

j++;

}

printf("%d->%d ",adjvex[k],k);

lowcost[k]=0;//等于0的话代表这个顶点已经加入生成树 下次取权值不会在用到它。

//更新lowcost数组

for (j = 0; jvexnum ; j++) {

if(lowcost[j]!=0&&G->arc[k][j]

lowcost[j]=G->arc[k][j];

adjvex[j]=k;

}

}

}

}

int main(){

initMGraph(G);

PRIM(G);

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值