Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪婪算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。
2.算法简单描述
1).记Graph中有v个顶点,e个边
2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边
3).将原图Graph中所有e个边按权值从小到大排序
4).循环:从权值最小的边开始遍历每条边 直至图Graph中所有的节点都在同一个连通分量中
if 这条边连接的两个节点于图Graphnew中不在同一个连通分量中
添加这条边到图Graphnew中
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
#define MAXEDGE 100
#define MAXVEX 100
#define INFINITY 65535
struct MGraph
{
char V[10];
int Edge[10][10];
int Vexnum;
int Edgenum;
};
void CreateGraph(MGraph *G) //初始化邻接矩阵
{
printf("请输入顶点数和边数:");
scanf("%d%d",&(G->Vexnum),&(G->Edgenum));
char c;
c=getchar();
int i,j;
for(i=0;i<G->Vexnum;i++)
for(j=0;j<G->Vexnum;j++)
G->Edge[i][j]=INFINITY;
printf("请输入顶点信息(char)型\n");
for(i=0;i<G->Vexnum;i++)
scanf("%c",&(G->V[i]));
c=getchar();
int w;
for(int k=0;k<G->Edgenum;k++)
{
printf("请输入(vi,vj)的下标i,j和权值w:");
scanf("%d%d%d",&i,&j,&w);
c=getchar();
G->Edge[i][j]=w;
G->Edge[j][i]=w;
}
}
struct Edge
{
int begin;
int end;
int weight;
};
int Find(int *parent,int f)
{
while(parent[f]>0)
f=parent[f];
return f;
}
bool comp(const Edge &e1,const Edge &e2)
{
return e1.weight<e2.weight;
}
void Kruskal(MGraph G)
{
int i,j,n,m;
Edge edges[MAXEDGE];//边集数组
int k=0;
for(i=0;i<G.Vexnum;i++)
for(j=i;j<G.Vexnum;j++)//j=0的话,因为是无向图,同一条边会当成两条
{
if(G.Edge[i][j]!=INFINITY)
{
edges[k].begin=i;
edges[k].end=j;
edges[k].weight=G.Edge[i][j];
k++;
}
}
sort(edges,edges+G.Edgenum,comp);//按权值从小到大排列
int parent[MAXVEX];
for(i=0;i<G.Vexnum;i++)
parent[i]=0;
for(i=0;i<G.Edgenum;i++)
{
n=Find(parent,edges[i].begin);
m=Find(parent,edges[i].end);
if(n!=m)
{
parent[n]=m;
printf("(%c,%c) %d\n",G.V[edges[i].begin],G.V[edges[i].end],edges[i].weight);//打印边和权值
}
}
printf("\n");
}
void main()
{
MGraph G;
CreateGraph(&G);
Kruskal(G);
}
原图:
生成树结果: