算法思路:
直接以边为目标去构建,直接去找最小权值的来构建生成树也是很自然的想法。
只需在构建时小心不要形成环路即可。自然地用到了边集数组。
运行结果↓:
<<<想看代码吗 ? 在最下面 >>>
//精华分析:之 一步一步分析代码: 污深深带你浪哟带你飞
因为一条边由两个顶点组成,我们把一条边的前后两个顶点按大小排好,填入edges方格列表,暂且 一个叫前点,一个叫后点。
定义的parent 数组 类比 普里姆中的 adjvex 与 lowcost 数组。
比如parent[2] = 5,并不单纯,
既然加入了parent[ ]数组,说明你已经 被 生成树 接收了,但是克鲁斯卡尔 生成树要的是边啊,咋办呢??
看代码:
if(n!=m)
parent[n]=m;
他的意思是 : parent[2] = 5 表示 (2,5)这条边入生成树。
一箭双雕,一石二鸟,一枪两妾真是厉害了,心机BOY。。。
回到Find() 函数
讲解:while ( parent[f] ! = 1 )
{
–因为edges方格列表是按大小次序来排的,所以检验时即可以优先检验 begin 域 (毕竟我们人为的按由小到大 对begin域和end域进行了排列),
倘若 parent[f] 不等于 -1 ;说明 以 2 为前点的某个边已经入生成树了,这时候我们要特别小心,以免他们互相勾搭生成环。所以就有了后面的检验:
f = parent [ f ] ;
将parent[ f ] (后点) 重新赋给 f ,要是while 还能循环,说明这几个点都是有线连着的,这就太危险啦!!
比如:前几次 loop Find函数的while 循环没执行,说明几个入树的节点并不相连。loop 1~~loop4 入树的是:(0,2);(3,5);(1,4);(2,5)。但是后来到 loop 5(循环 5 )的时候,发生了一些节点相连接的事情。
loop 5 时,(0,3) 想入树,但大家看出它好像跟 (0,2);(3,5) 都有一腿,
动用审查代码:f = parent [ f ] ; 直到parent[5] == -1
说明并不是死循环啊,说明好像不成环,这才罢休。
而后是终极审查!!! 。(下面有句话说错了,应该是要是万一几个节点不相连)
看上图 if(n != m)
说明从不同的出口出来,也就最终说明不会构成回路,
但若是n = m 你们丫都穿一条裤子了,这构成环路乱搞的事情算是板上钉钉了。
来人啊!乱棍打出生成树学习小组!!!
就这么,(0,3)再也没有了进入生成树的机会。。。。。。
( 其他的以此类推即可 )
<<<——–下面是代码君———>>>
#include <stdio.h>
#include <stdlib.h>
#define MAXEDGE 10
#define MAXVEX 6
/*定义边集数组*/
struct Edge{
int begin;
int end;
int weight;
};
struct MGraph{
int numVertexes;
int numEdges;
int *vex;
Edge *edges;
};
int Find(int *parent,int f)
{ /*结点f与parent[f]是否连接(或者间接即多跳连接)着(在边子集中)同一个结点*/
while(parent[f]!=-1) /*循环!loop!*/
f=parent[f];
return f;
}
int IsCompleted(int *parent)
{
int i;
int n=0;
for(i=0;i<MAXVEX;++i)
{
if(parent[i]!=-1)
++n;
}
if(n==MAXVEX-1) //最小生成树的特点是n各节点有n-1条边
return 1;
else
return 0;
}
void MiniSpanTree_Kruskal(MGraph *G)
{
int i,n,m;
//Edge edges[MAXEDGE]; //边集数组
int parent[MAXVEX];
for(i=0;i<G->numVertexes;++i)
parent[i]=-1;
for(i=0;i<G->numEdges;++i)
{
n=Find(parent,G->edges[i].begin);
m=Find(parent,G->edges[i].end);
/*判断结点edges[i].begin与edges[i].end是否连接(或者间接即多跳连接)着(在边子集中)同一个结点*/
/*注意:假设结点edges[i].begin与结点edges[i].end都跟量外一个结点X相连(或者间接相连),如若不加判断,则三个结点会形成回路*/
/*if(n!=m && parent[n]!=m)*/
if(n!=m)
{
parent[n]=m;
printf("(%d,%d) %d\n",G->edges[i].begin,G->edges[i].end,G->edges[i].weight);
}
//怎么判断生成树已连通原图,即已生成生成树
if(IsCompleted(parent))
return;
}
}
int main()
{
MGraph *my_g = (struct MGraph*)malloc(sizeof(struct MGraph));
int i,j;
int t = 0;
my_g->numVertexes = 6;
my_g->numEdges = 10;
my_g->vex = (int*)malloc(sizeof(char)*my_g->numVertexes);
if(!my_g->vex)
return -1; //原式是return;
for(i = 0 ; i < my_g->numVertexes ; ++i)
//一维数组(图中各结点编号)初始化{0,1,2,3,4,5}
my_g->vex[i] = i ;
my_g->edges = (Edge*)malloc(sizeof(Edge)*MAXEDGE);
if(!my_g->edges)
return -1; //原式是return;
//简单起见,边集数组(按边的权值从小到大排序)直接输入
my_g->edges[0].begin=0; my_g->edges[0].end=2; my_g->edges[0].weight=1;
my_g->edges[1].begin=3; my_g->edges[1].end=5; my_g->edges[1].weight=2;
my_g->edges[2].begin=1; my_g->edges[2].end=4; my_g->edges[2].weight=3;
my_g->edges[3].begin=2; my_g->edges[3].end=5; my_g->edges[3].weight=4;
my_g->edges[4].begin=0; my_g->edges[4].end=3; my_g->edges[4].weight=5;
my_g->edges[5].begin=1; my_g->edges[5].end=2; my_g->edges[5].weight=5;
my_g->edges[6].begin=2; my_g->edges[6].end=4; my_g->edges[6].weight=5;
my_g->edges[7].begin=0; my_g->edges[7].end=1; my_g->edges[7].weight=6;
my_g->edges[8].begin=4; my_g->edges[8].end=5; my_g->edges[8].weight=6;
my_g->edges[9].begin=2; my_g->edges[9].end=3; my_g->edges[9].weight=7;
MiniSpanTree_Kruskal(my_g);
}
——————————-全剧终—————————————-
这篇博客写的蛮爽的。。
来啊!点赞啊!
来啊!关注啊~~
————————取材《大话数据结构》
—————————–《鱼c –数据结构与算法》
—-coding感谢: htp://blog.csdn.net/ppalive_/articledetails/47761015