动画参考视频:最小生成树(Kruskal(克鲁斯卡尔)和Prim(普里姆))算法动画演示_哔哩哔哩_bilibili

克鲁斯卡尔算法(Kruskai)

克鲁斯卡尔算法,从边的角度求网的最小生成,时间复杂度为O(eloge)。和普里姆算法恰恰相反,更适合于求边稀疏的网的最小生成树。

思路步骤:      

1、将边全部提取出来放入一个列表中,从权重小到大依次排序

2、将最小权重的边放入图中与对应的顶点相连

3、要确保边填入后不能形成环,如果形成环就丢弃这条边

4、知道加入了(n-1)条边最小生成树构造完成。(n是树中顶点的数量)

普里姆算法(Prim)

普里姆算法。该算法从顶点的角度为出发点,时间复杂度O(n2),更适合与解决边的绸密度更高的连通网。

思路步骤:

1、从顶点开始出发,选择权重最小的边连接。

2、连接完新的顶点后继续找最小权重边,与已经连接的全部顶点所连接的边都要对比。

3、连接后判断是否形成环,形成的话则放弃,回退权重第二小的边以此类推。

代码没有完善仅供参考

/* 参考的结构体
typedef struct Edgenode		//邻接结点 
{
	int adjvex;				//邻接结点存储的数组下标 
	int weight;				//用于存储权值,对于非网图可以不需要
	struct Edgenode *next;	//链域,指向下一个邻接点
}Edgenode;
 
typedef struct Vertexnode	//顶点 表节点 
{
	char data;				//顶点域,存储顶点信息
	Edgenode *firstedge;	//边表头指针
}Vertexnode,AdjList[Maxvew];
 
typedef struct				// 数组、顶点、边 结构体 
{
	AdjList adjList;		//顶点数组 
	int numVertexes,numEdges;//图中当前顶点数和边数
}GrapAdList;
*/  //以上仅供参考 
// Prim算法生成最小数
void MIniSpanTree_prim(MGraph G)
{
	int min,i,j,k;			
	int adjvex[MAXVEX];		//保存相关顶点下标 
	int lowcost[MAXVEX];	//保存相关顶点间边的权值 
	
	lowcost[0] = 0;			//V0作为最小生成树的根开始遍历 , 权值为0 
	adjvex[0] = 0;			//V0第一个加入 
	
	//初始化操作
	for(i=1;i<G.numVertexes;i++)
	{
		lowcost[i]=G.arc[0][i];		//将邻接矩阵的第0行所有权值先加入数组 
		adjvex[i]=0;				//初始化全部先为V0的下标 
	} 
	
	//真正构造最小生成树的过程
	for(i=1;i<G.numVertexes;i++)
	{
		min=INFINITY;		// 初始化最小权值为 65535 等不可能数值 
		j=1;
		k=0;
		
		//遍历全部顶点
		while(j<G.numVertexes)
		{
			//找出lowcost数组已储存的最小权值 
			if(lowcost[j]!=0 && lowcost[j]<min)
			{
				min= lowcost[j];
				k=j;			// 将发行的最小权值的下标存入k ,以待使用 
			}
			j++;
		} 
		//打印当前顶点边中权值最小的边 
		printf("(%d,%d)",adjvex[k],k);
		lowcost[k]=0;          //将当前顶点权值全部设置为 0 ,表示此顶点已经完成任务,进行下一个顶点的遍历 
		
		//邻接矩阵k行逐个遍历全部顶点 
		for(j=1;j<G.numVertexes;j++)
		{
			if(lowcost[j]!=G.numVertexes;j++)
			{
				lowcost[j]=G.arc[k][j];
				adjvex[j]=k;
			}
		}
	}
} 

//Kruskal算法最小生成树的过程
int Find(int *parent , int f)
{
	while(parent[f]>0)
	{
		f=parent[f];
	}
	
	return f;
} 

void MIniSpanTree_Kruskal(MGraph G)
{
	int i,n,m;
	Edge edges[MAGEDGE];		//定义边集数组 
	int parent[MAXVEX];			//定义parent数组用来判断边与边是否形成环路 
	
	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(n!=m)		//如果n==m,则形成环路,不满足! 
		{
			parent[n]=m;//将此边的结尾顶点放入下标为起点的parent数组中,表示此顶点已经在生成树集合中 
			printf("(%d,%d) %d",edges[i].begin,edges[i].end,edges[i].weight);
		}
	}
}