最小生成树--kruskal算法

kruskal算法形成最小生成树

prim是以顶点为中心,而kruskal算法是以边为中心。每次找到不会形成环路的最小的边。

具体实现:

#include <stdlib.h>
#include <stdio.h>
#define INFINITY 100
typedef struct
{
    int vexs[9];
 int arc[9][9];
 int numVertexes,numEdges;
}MGragh;

typedef struct
{
    int begin ;
 int end;
 int weight;
}Edge;
Edge edge[15];// edge不能在sort函数内部定义,因为是局部变量,返回时,edge[]会销毁,得到内容为随机数,必须是全局变量,或者从main函数中传入。
void CreateGragh(MGragh *G)
{
 int i,j,k,w;
 printf("input the vex and edges:");
 scanf("%d%d",&G->numVertexes,&G->numEdges);
 for (i=0; i<G->numVertexes; i++)
  G->vexs[i]=i;

 for (i=0; i<G->numVertexes; i++)
  for (j=0; j<G->numVertexes; j++)  
  {
   G->arc[i][j]=INFINITY;
         G->arc[i][i]=0;
  }
 printf("input the (i,j)edge's value:\n");
 for(k=0; k<G->numEdges;k++) 
 {
   scanf("%d%d%d",&i,&j,&w);
   G->arc[i][j]=w;
   G->arc[j][i]=G->arc[i][j];
 }
}
Edge* sort(MGragh *G)
{  
 int min,k=0,tmpbegin,tmpend,tmpvalue;
 int i=0,j=0;
 // 将邻接矩阵转换为edge[]数组
 for(i=0; i<G->numVertexes; i++)
  for(j=i+1; j<G->numVertexes;j++)
  {
   if(G->arc[i][j]!=INFINITY)
   {
    edge[k].begin=i;
    edge[k].end=j;
    edge[k].weight=G->arc[i][j];
    k++;
    //printf("(%d,%d)%d \n",edge[i].begin,edge[i].end,edge[i].weight);
   }
  }
   
 //对边集数组edge[]按权值从小到大排序
  for(i=0; i<G->numEdges-1; i++)
  {
   min=edge[i].weight;
   k=i;
   for(j=i+1; j<G->numEdges; j++)
   {
    if(edge[j].weight<min)
    {
        k=j;
     min=edge[j].weight;
    }
   }
   tmpbegin=edge[k].begin;
   edge[k].begin=edge[i].begin;
   edge[i].begin=tmpbegin;

   tmpend=edge[k].end;
   edge[k].end=edge[i].end;
   edge[i].end=tmpend;

   tmpvalue=edge[k].weight;
   edge[k].weight=edge[i].weight;
   edge[i].weight=tmpvalue;
  }

  //for(i=0; i<G->numEdges; i++) 
  //printf("%d,(%d,%d)%d \n",i,edge[i].begin,edge[i].end,edge[i].weight);
 return edge;
}

int find(int *parent, int f)
{
 while(parent[f]>0)
  f=parent[f];
 return f;
}

void MiniTree_Kruskal(MGragh *G)
{
 Edge *edge;
 int i,n,m;
 int parent[9];
 edge=sort(G);

//准备工作完成,开始进行
 for(i=0; i<G->numVertexes; i++)
  parent[i]=-1; // 初始状态,只有n个顶点的无边非连通图,写0也可以,但是因为有顶点0,所以,避免扰乱,改为-1
 for(i=0; i<G->numEdges; i++)
 {
  n=find(parent,edge[i].begin);
  m=find(parent,edge[i].end);
     if(n!=m)
  {
      parent[n]=m;
   printf("(%d,%d) %d",edge[i].begin,edge[i].end,edge[i].weight);
  }
 }
}

void main()
{
 MGragh *gragh;
 gragh=(MGragh *)malloc(sizeof(MGragh));
 CreateGragh(gragh);
 MiniTree_Kruskal(gragh);
 system("pause");
}

 输入:9 15

0 1 10
0 5 11
1 2 18
1 6 16
1 8 12
2 3 22
2 8 8
3 4 20
3 6 24
3 7 16
3 8 21
4 5 26
4 7 7
5 6 17
6 7 19

输出:(4,7) 7       (2,8) 8       (0,1) 10      (0,5) 11        (1,8) 12          (1,6) 16         (3,7) 16          (6,7) 19

 

kruskal算法中有个重要的数组parent[MAXVEX],用来判断是否会形成回路。

最重要的是弄清楚parent[i]数组表示的意义。该数组的内容i表示顶点,该数组的值表示与该顶点i直接或者间接相连。如parent[0]=1,表示v0v1顶点(直接或者通过中间结点)相连形成边。

那么它是如何判断回路呢?

以对边集定义的数据结构出发:

typedef struct

{

    int begin;

    int end;

    int weight;

}Edge;

首先,将邻接矩阵对应的边集转换为按升序排列的Edge类型的数组 edges[MAXEDGE],从某条边的begin点,一步步找到从begin点已经连接的点,直到某个点不再与其他点连接,记该点为parent[k]=0,等于说以begin点为起始点,向已经连接的点寻找,该线路断与k点。

同理,以end点为起始的点,一步步向已经连接的点寻找,若也有parent[k]=0;则按照以begin/end为起点的点不断向上查找,可以找到从begin到end点之间存在通路,然而,以begin和end两点之间本身就是一条边。因而会形成环路。

for(i=0; i<G.numVertexes; i++)

      parent[i]=0;  //初始化,没有边关系。

 

for(i=0; i<G.numEdges; i++)

{

    n=find(parent,edges[i].begin);

   m=find(parent,edges[i].end);

   if(m != n)

   {

         parent[n]=m;

         printf("(%d,%d)  %d",edges[i].begin, edges[i].end, edges[i].weight);

   }

}

 

int find(int *parent,int f)

{

    while(parent[f]>0)

           f=parent[f];

    return f;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值