Kruskal算法的设计与实现

来源:互联网 发布:英文翻译中文软件下载 编辑:程序博客网 时间:2024/05/16 10:55

[功能模块]
/*  Kruskal算法的设计与实现 (WIN-TC调试通过)*/
#include "stdio.h"
#include "conio.h"
#define MAX 30
typedef struct
{ int v1,v2;          /*每条边的两个顶点*/
  int weight;         /*边的权值*/
}EDGE;

typedef struct      
{ int vnum;          /*图的顶点数目*/
  EDGE e[MAX*(MAX-1)/2];    /*图中的边*/
}Graph;

typedef struct node
{ int v;                 /*用链表存储同一个连通分量的顶点*/
  struct node *next;
}Alist;

void heapadjust(EDGE data[],int s ,int m)
{ /*将元素序列data[s..m]调整为小根堆,堆顶元素为data[s]*/
  int j;
  EDGE t;
  t=data[s];            /*备份元素data[s],为其找到适当位置后插入*/
  for(j=2*s+1;j<=m;j=j*2+1)        /*沿值较小的孩子结点向下筛选*/
  { if(j<m && data[j].weight>data[j+1].weight) j++;
    if(!(t.weight>data[j].weight)) break;
    data[s]=data[j];s=j;        /*用s记录待插入元素的位置*/
  }
  data[s]=t;             /*将备份元素插入由s所指出的位置*/
}

int creatgraph(Graph *p)  /*输入图的顶点数和边数,创建一个图并返回图的边数*/
{ int n,m,v1,v2,w,k=0;
  printf("输入图的顶点数:");
  scanf("%d",&n);
  if(n<1) return 0;
  p->vnum=n;
  printf("输入图的边数: ");
  scanf("%d",&m);
  while(k<m)
  { printf("输入第 %d 条边的两个顶点和权值:",k+1);
    scanf("%d%d%d",&v1,&v2,&w);
    /*if(v1>=0 && v1<n && v2>=0 && v2<n)*/
     p->e[k].v1=v1;p->e[k].v2=v2;
     p->e[k].weight=w;k++;

  }
  return m;
}

int kruskal(Graph G,int enumber,int tree[][3]) /*用kruskal算法求图G的最小生成树,返回其代价*/
{ int i,k,m,cost=0;
  int v1,v2;
  Alist *p,*q,*a[MAX];
  for(i=0;i<G.vnum;i++)     /*将每个连通分量的顶点存放在一个单链表中*/
  { a[i]=(Alist *)malloc(sizeof(Alist));
    a[i]->v=i;a[i]->next=NULL;
  }
  for(i=enumber-1;i>=0;i--)    /*按边上的权值建立小根堆*/
    heapadjust(G.e,i,enumber-1);
  k=G.vnum;                  /*k用于计算图中连通分量的数目*/
  m=enumber-1;
  i=0;
  do
  { v1=G.e[0].v1;v2=G.e[0].v2;
    p=a[v1];
    while(p && p->v!=v2)    /*判断当前所选择边的顶点是否在同一个连通分量中*/
    { q=p;p=p->next;}
    if(!p)                  /*如果不在同一个连通分量中*/
    { p=q;
      p->next=a[G.e[0].v2];
      p=a[G.e[0].v1];       /*加入边(v1,v2),将两个连通分量合并为一个*/
      while(p){a[p->v]=a[G.e[0].v1];p=p->next;}
      k--;                  /*连通分量数目减少一个*/
      tree[i][0]=v1;        /*加入最小生成树中*/
      tree[i][1]=v2;
      tree[i][2]=G.e[0].weight;
      cost+=G.e[0].weight;
      i++;
    }/*if*/
    G.e[0]=G.e[m];
    m--;
    heapadjust(G.e,0,m); /*找下一条权值最小的边*/
  }while(k>1);  /*当所有的顶点不在同一个连通分量时,继续循环*/
  return cost;
}

main()
{ int i,enumber,cost=0;
  int tree[MAX][3];
  Graph G;
  enumber=creatgraph(&G);
  cost=kruskal(G,enumber,tree);
  printf("/n输出最小生成树的边集:/n");
  for(i=0;i<G.vnum-1;i++)
    printf("%d/t%d/t%d/n",tree[i][0],tree[i][1],tree[i][2]);
  printf("/n最小生成树的成本为: %d" ,cost);
  getch();
}

[测试方案]
假设有以下无向连通图: 


   用以上数据进行测试,程序的运行结果如下:
  

输入图的顶点数:4

输入图的边数:  6

输入第1条边的顶点和权值:1  2  10

输入第2条边的顶点和权值:1  3  75

输入第3条边的顶点和权值:1  4  20

输入第4条边的顶点和权值:2  3  85

输入第5条边的顶点和权值:2  4  40

输入第6条边的顶点和权值:3  4  35

输出最小生成树的边集:

    1      2      10

    1      4      20

    3      4      35

最小生成树的成本为:65

 

由程序的运行结果可以验证所设计的算法是正确的。
原创粉丝点击