Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)

Q1.1、举一个实例,画出采用Prim算法构造最小生成树的过程,并编写算法。
Q1.2、 举一个实例,画出采用Kruskal算法构造最小生成树的过程,并编写算法。

Prim算法

第一步:随意选取起点

图中有6个顶点v1-v6,集合表示为:V={v1,…,V6},每条边的边权值都在图上;在进行prim算法时,我们先随意选择一个顶点作为起始点(起始点的选取不会影响最小生成树结果),在此一般选择v1作为起始点,设U集合为当前所找到最小生成树里面的顶点,TE集合为所找到的边。
Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第1张图片

U={v1}; TE={}

第二步:在前一步的基础上寻找最小权值

查找一个顶点在U={v1}集合中,另一个顶点在V-U集合中的最小权值,如下图,在红线相交的线上找最小值。

通过图中我们可以看到边v1-v2的权值最小为1,那么将v2加入到U集合,(v1,v2)加入到TE。

Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第2张图片

U={v1,v2}; TE={(v1,v2)}

第三步:继续寻找最小权值

继续在前一步的基础上,寻找最小权值,如此循环一下直到找到所有顶点为止。
Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第3张图片
Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第4张图片
Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第5张图片
Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第6张图片
U={v1,v2,v3,v6,v5,v4};
TE={(v1,v2),(v2,v3),(v2,v6),(v6,v5),
(v5,v4)}

注意事项:
(1)每次都选取权值最小的边,但不能构成回路,构成环路的边则舍弃。
(2)遇到权值相等,又均不构成回路的边,随意选择哪一条,均不影响生成树结果。
(3)选取n-1条恰当的边以连通n个顶点。

代码实现

#define MAX  100000
#define VNUM  10+1

int edge[VNUM][VNUM]={/*输入的邻接矩阵*/};
int lowcost[VNUM]={0};
int addvnew[VNUM];
int adjecent[VNUM]={0};
void prim(int start)
{
     int sumweight=0;
     int i,j,k=0;

     for(i=1;i<VNUM;i++)//顶点是从1开始
     {
        lowcost[i]=edge[start][i];
        addvnew[i]=-1;
     }
     addvnew[start]=0;//将起始点start加入VNUM
     adjecent[start]=start;
     for(i=1;i<VNUM-1;i++)                                        
     {
        int min=MAX;
        int v=-1;
        for(j=1;j<VNUM;j++)                                      
        {
            if(addvnew[j]!=-1&&lowcost[j]<min) 
            {
                min=lowcost[j];
                v=j;
            }
        }
        if(v!=-1)
        {
            printf("%d %d %d\n",adjecent[v],v,lowcost[v]);
            addvnew[v]=0;
            sumweight+=lowcost[v];//计算路径长度之和
            for(j=1;j<VNUM;j++)
            {
                if(addvnew[j]==-1&&edge[v][j]<lowcost[j])      
                {
                    lowcost[j]=edge[v][j];                     
                    adjecent[j]=v;                             
                }
            }
        }
    }
    printf("the minmum weight is %d",sumweight);
}

Kruskal算法

克鲁斯卡尔算法的具体思路是:将所有边按照权值的大小进行升序排序,然后从小到大一一判断,条件为:如果这个边不会与之前选择的所有边组成回路,就可以作为最小生成树的一部分;反之,舍去。直到具有 n 个顶点的连通网筛选出来 n-1 条边为止。筛选出来的边和所有的顶点构成此连通网的最小生成树。

第一步:标记

在初始状态下,对各顶点赋予不同的标记(用颜色区别)
Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第7张图片

第二步:排序
遍历所有顶点,对所有边按照权值的大小进行排序,按照从小到大的顺序进行判断
Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第8张图片
Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第9张图片
第三步:得到最小生成树

当选取的边的数量相比与顶点的数量小 1 时,说明最小生成树已经生成。所以最终采用克鲁斯卡尔算法得到的最小生成树
Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码)_第10张图片
代码实现

typedef struct          
{        
    char vertex[VertexNum];
    int edges[VertexNum][VertexNum];        
    int n,e;
}MGraph; 
 
typedef struct node  
{  
    int u,v,w;
}Edge; 

void kruskal(MGraph G)  
{  
    int i,j,u1,v1,sn1,sn2,k;  
    int vset[VertexNum];//判定两个顶点是否连通   
    int E[EdgeNum];/ 
    k=0;
    for (i=0;i<G.n;i++)  
    {  
        for (j=0;j<G.n;j++)  
        {  
            if (G.edges[i][j]!=0 && G.edges[i][j]!=INF)  
            {  
                E[k].u=i;  
                E[k].v=j;  
                E[k].w=G.edges[i][j];  
                k++;  
            }  
        }  
    }     
    heapsort(E,k,sizeof(E[0]));//堆排序       
    for (i=0;i<G.n;i++)//初始化辅助数组   
    {  
        vset[i]=i;  
    }  
    k=1;
    j=0;  
    while (k<G.n)  
    {   
        sn1=vset[E[j].u];  
        sn2=vset[E[j].v]; 
        if (sn1!=sn2)  
        {
            printf("%d--->%d, %d",E[j].u,E[j].v,E[j].w);       
            k++;  
            for (i=0;i<G.n;i++)  
            {  
                if (vset[i]==sn2)  
                {  
                    vset[i]=sn1;  
                }  
            }             
        }  
        j++;  
    }  
}

你可能感兴趣的:(Q1.用Prim算法和Kruskal算法构造最小生成树(过程+代码))