克鲁斯卡尔算法(Kruskal)

来源:互联网 发布:qq群搜索排名优化 编辑:程序博客网 时间:2024/04/26 03:59

  克鲁斯卡尔(Kruskal)算法是一种按权值的递增次序选择合适的边来构造最小生成树的方法。假设G=(V,E)是一个具有n个顶点的带权连通图,T=(U,TE)G的最小生成树,则构造最小生成树的步骤如下:
  1) 设置U的初值等于V(即包含有G中的全部顶点), TE的初值为空集(即图T中每一个顶点都构成一个分量)。
  2) 将图G中的边按权值从小到大的顺序依次选取。若选取的边没有使树T生成回路,则将该边加入TE; 否则舍弃,直到TE包含(n1)条边为止。
  实现克鲁斯卡尔算法的关键是,如何判断选取的边是否与生成树中已保留的边形成回路,这可以通过判断边的两个顶点所在的连通分量的方法来解决。
  为此设置一个辅助数组vset[0..n1], 它用于判定两个顶点之间是否连通。数组元素vset[i](初值为i)代表序号为i的顶点所属的连通顶点集的编号(当选中不连通的两个顶点间的一条边时,它们分属的两个顶点集合按其中的一个编号)。当两个顶点的集合编号不同时,加入这两个顶点构成的边到最小生成树时一定不会形成回路。
  采用E数组存放图G中的所有边,采用直接插入排序的方法将所有边按权值从小到大的顺序排列。E数组元素类型如下:  

typedef struct {   int u;              //边的起始顶点    int v;              //边的终止顶点    int w;              //边的权值      } Edge;

Kruskal算法如下:

void SortEdge(MGraph g,Edge E[])    //从邻接矩阵产生权值递增的边集{    int i,j,k=0;    Edge temp;    for (i=0;i<g.vexnum;i++)        for (j=0;j<g.vexnum;j++)            if (g.edges[i][j]<INF)            {                E[k].u=i;                E[k].v=j;                E[k].w=g.edges[i][j];                k++;            }    for (i=1;i<k;i++)   //按权值递增有序进行直接插入排序     {        temp=E[i];        j=i-1;          //从右向左在有序区E[0..i-1]中找E[i]的插入位置        while (j>=0 && temp.w<E[j].w)         {               E[j+1]=E[j]; //将权值大于E[i].w的记录后移            j--;        }        E[j+1]=temp;      //在j+1处插入E[i]    }}void Kruskal(Edge E[],int n,int e){    int i,j,m1,m2,sn1,sn2,k;    int vset[MAXE];    for (i=0;i<n;i++) vset[i]=i;    //初始化辅助数组    k=1;                            //k表示当前构造最小生成树的第几条边,初值为1    j=0;                            //E中边的下标,初值为0    while (k<n)                     //生成的边数小于n时循环    {           m1=E[j].u;m2=E[j].v;        //取一条边的头尾顶点        sn1=vset[m1];sn2=vset[m2];  //分别得到两个顶点所属的集合编号        if (sn1!=sn2)               //两顶点属于不同的集合,该边是最小生成树的一条边        {               printf("  (%d,%d):%d\n",m1,m2,E[j].w);            k++;                    //生成边数增1            for (i=0;i<n;i++)       //两个集合统一编号                if (vset[i]==sn2)   //集合编号为sn2的改为sn1                    vset[i]=sn1;        }        j++;                        //扫描下一条边    }}

  克鲁斯卡尔算法的时间复杂度为O(eloge), 这个e是图的边数,它的时间复杂度与顶点数n无关,只与边数e有关,该算法适用于稀疏图。
  

1 0