c/c++语言开发共享数据结构(C实现)——- 最小生成树之Kruskal算法

  算法描述: kruskal算法是按权值递增的次序来构造最小生成树的方法。    假设g(v,e)最一个具有n个顶点的连通网,顶点集v={v1,v2,….,vn}。设所求的最


 

算法描述:

kruskal算法是按权值递增的次序来构造最小生成树的方法。

   假设g(v,e)最一个具有n个顶点的连通网,顶点集v={v1,v2,….,vn}。设所求的最小生成树为t={u,te},其中u是t的顶点集,te是t的边集,u和te的初始值为空集。kruskal算法的基本思想如下:将最小生成树初始化为t=(v,te),仅包含 g的全部顶点,不包含g的任一条边,此时,t由n 个连通分量组成,每个分量只有一个顶点;将图中g中的边按权值从小到大排序,选择代价最小了一条边,若该边所依附的顶点分属于t中的不同的连通分量,则将此边加入到te中,否则,舍弃此边而选择下一条代价最小的边。依次类推,直至te中包含n-1条边(即t中所有的顶点都在同一连通分量上)为止。

 

算法实现:

   设置一个edge数组存储连通网中所有的边,为了便于选择当前权值最小的边,需要将edge中的边按权值从小到大进行排列。

   而在连通分量的合并上,可以采用集合的合并方法,对于有n个顶点的连通网,设置一个数组father[0…n-1],其初始值为-1,表示n个顶点在不同的连通分量上。然后,依次扫描edge数组中的每一条边,并查找相关联的两个顶点所属的连通分量,假设vf1和vf2为两个顶点的所在树的根节点的序号,若vf1不等于vf2,则表明这条边的两个顶点不属于同一个连通分量,则将这条边作为最小生成树的边并输出,然后合并它们所属的两个连通分量。

 

算法代码:

 

 int findfather(int father[],int v){ 	int t = v; 	while(father[t] != -1) 		t = father[t]; 	return t; }    /* *  *kruskal算法求最小生成树  * */  void kruskal_mg(mgraph mg,edge edge[]){ 	int father[max_vex_num]; 	int i,count,vf1,vf2; 	// 初始化father数组 	for(i = 0;i < max_vex_num;i++){ 		father[i] = -1; 	} 	i = 0; 	count = 0; // 统计加入最小生树中的边数 	// 遍历任意两个结点之间的边 	while(i < mg.arcnum && count < mg.arcnum){ 		vf1 = findfather(father,edge[i].start); 		vf2 = findfather(father,edge[i].end); 		// 如果这两个节点不属于同一个连通分量,则加入同一个连通分量 		if (vf1 != vf2){ 			father[vf2] = vf1; 			count++; 			printf(%c,%c,%d ,mg.vexs[edge[i].start],mg.vexs[edge[i].end],edge[i].cost); 		} 		i++; 	} }

   其中,函数findfather的作用就是找指定节点所属的连通分量,在这里也就是找其所在树的根节点在数组中的序号。

 

 

算法说明:

   对于带权图g中e条边的权值的排序方法可以有多种,这里采用的是最简单的冒泡排序法,时间复杂度为o(n^2)。而判断新选择的边的两个顶点是否在同一个连通分量中,这个问题等价于一个在最多有n 个顶点的生成树中遍历寻找新选择的边的两个节点是否存在的问题,所以此算法的复杂度最坏情况下是o(n^2)。

   注意:一般来讲,prim算法的时间复杂度为o(n^2),因此适合于稠密图,而kruskal算法需要对e条边进行排序,最快的情况下复杂度为o(elog2e),因此对于稀疏图,采用kruskal算法比较合适。

 

完整代码:

 

 /*  * =====================================================================================  *  *       filename:  kruskal.c  *  *    description:  最小生成树之kruskal算法  *  *        version:  1.0  *        created:  2015年05月06日 21时25分12秒  *       revision:  none  *       compiler:  gcc  *  *         author:  jesson20121020 (), 997287955@qq.com  *   organization:    *  * =====================================================================================  */   #include  #include  #define max_vex_num 50 #define max_arc_num 100 #define un_reach 1000     typedef char vertextype; typedef enum { 	dg, udg } graphtype; typedef struct { 	vertextype vexs[max_vex_num]; 	int arcs[max_vex_num][max_vex_num]; 	int vexnum, arcnum; 	graphtype type; } mgraph;    /**  * 根据名称得到指定顶点在顶点集合中的下标  * vex  顶点  * return 如果找到,则返回下标,否则,返回0  */ int getindexofvexs(char vex, mgraph *mg) { 	int i; 	for (i = 1; i <= mg->vexnum; i++) { 		if (mg->vexs[i] == vex) { 			return i; 		} 	} 	return 0; }  /**  * 创建邻接矩阵  */ void create_mg(mgraph *mg) { 	int i, j, k,weight; 	int v1, v2, type; 	char c1, c2; 	printf(please input graph type dg(0) or udg(1) :); 	scanf(%d, &type); 	if (type == 0) 		mg->type = dg; 	else if (type == 1) 		mg->type = udg; 	else { 		printf(please input correct graph type dg(0) or udg(1)!); 		return; 	}  	printf(please input vexmun : ); 	scanf(%d, &mg->vexnum); 	printf(please input arcnum : ); 	scanf(%d, &mg->arcnum); 	getchar(); 	for (i = 1; i <= mg->vexnum; i++) { 		printf(please input %dth vex(char):, i); 		scanf(%c, &mg->vexs[i]); 		getchar(); 	}  	//初始化邻接矩阵 	for (i = 1; i <= mg->vexnum; i++) { 		for (j = 1; j <= mg->vexnum; j++) { 			if(i == j) 				mg->arcs[i][j] = 0; 			else 				mg->arcs[i][j] = un_reach; 		} 	}  	//输入边的信息,建立邻接矩阵 	for (k = 1; k <= mg->arcnum; k++) { 		printf(please input %dth arc v1(char) v2(char) weight(int): , k);  		scanf(%c %c %d, &c1, &c2,&weight); 		v1 = getindexofvexs(c1, mg); 		v2 = getindexofvexs(c2, mg); 		if (mg->type == 1) 			mg->arcs[v1][v2] = mg->arcs[v2][v1] = weight; 		else 			mg->arcs[v1][v2] = weight; 		getchar(); 	}     } /**  * 打印邻接矩阵和顶点信息  */ void print_mg(mgraph mg) { 	int i, j; 	if(mg.type == dg){ 		printf(graph type: direct graph ); 	} 	else{ 		printf(graph type: undirect graph ); 	}  	printf(graph vertex number: %d ,mg.vexnum); 	printf(graph arc number: %d ,mg.arcnum);  	printf(vertex set:  ); 	for (i = 1; i <= mg.vexnum; i++) 		printf(%c	, mg.vexs[i]); 	printf( adjacency matrix: );  	for (i = 1; i <= mg.vexnum; i++) { 		j = 1; 		for (; j < mg.vexnum; j++) { 			printf(%d	, mg.arcs[i][j]); 		} 		printf(%d , mg.arcs[i][j]); 	} }   // 定义边结构体 typedef struct{ 	int start; 	int end; 	int cost; }edge;   /* *  * 由邻接矩阵得到边的信息  *  * */ void init_edge(mgraph mg,edge edge[]){ 	int i,j; 	int count = 0; 	if(mg.type == 0){ 		for(i = 1; i <= mg.vexnum;i++){ 			for (j = 1;j <= mg.vexnum;j++){ 				if(mg.arcs[i][j] != 0 && mg.arcs[i][j] != un_reach){ 					edge[count].start = i; 					edge[count].end = j; 					edge[count].cost = mg.arcs[i][j]; 					count++; 				} 			} 		} 	} 	else{ 		for(i = 1; i <= mg.vexnum;i++){ 			for (j = i;j <= mg.vexnum;j++){ 				if(mg.arcs[i][j] != 0 && mg.arcs[i][j] != un_reach){ 					edge[count].start = i; 					edge[count].end = j; 					edge[count].cost = mg.arcs[i][j]; 					count++; 				} 			} 		} 	} 	 }     /* *  * 将边按权值从大到小排序  * */ void sort_edge(edge edge[],int arcnum){ 	int i,j; 	edge temp; 	for(i = 0; i < arcnum - 1;i++){ 		for (j = i+1;j < arcnum;j++){ 			if(edge[i].cost > edge[j].cost){ 				temp = edge[i]; 				edge[i] = edge[j]; 				edge[j] = temp; 			} 		} 	} }  /* *  * 输出边的信息  * */ void print_edge(edge edge[],int arcnum){ 	int i = 0; 	while(i < arcnum){ 		printf(%d,%d,%d ,edge[i].start,edge[i].end,edge[i].cost); 		i++; 	} } /** *    找出指定节点的所属的连通分量,这里是找出其根节点在father数组中下标。 **/ int findfather(int father[],int v){ 	int t = v; 	while(father[t] != -1) 		t = father[t]; 	return t; }  /* *  *kruskal算法求最小生成树  * */  void kruskal_mg(mgraph mg,edge edge[]){ 	int father[max_vex_num]; 	int i,count,vf1,vf2; 	// 初始化father数组 	for(i = 0;i < max_vex_num;i++){ 		father[i] = -1; 	} 	i = 0; 	count = 0; // 统计加入最小生树中的边数 	// 遍历任意两个结点之间的边 	while(i < mg.arcnum && count < mg.arcnum){ 		vf1 = findfather(father,edge[i].start); 		vf2 = findfather(father,edge[i].end); 		// 如果这两个节点不属于同一个连通分量,则加入同一个连通分量 		if (vf1 != vf2){ 			father[vf2] = vf1; 			count++; 			printf(%c,%c,%d ,mg.vexs[edge[i].start],mg.vexs[edge[i].end],edge[i].cost); 		} 		i++; 	} } /**  * 主函数  */ int main(void) { 	mgraph mg; 	edge edge[max_arc_num]; 	create_mg(&mg); 	print_mg(mg); 	init_edge(mg,edge); 	sort_edge(edge,mg.arcnum); 	printf(the result of kruskal: ); 	kruskal_mg(mg,edge);  		 	 	return exit_success; }  

 

运行演示:

 

 jesson@jesson-k43sv:~/develop/worksapce/c_learning/最小生成树$ gcc -o kruskal kruskal.c jesson@jesson-k43sv:~/develop/worksapce/c_learning/最小生成树$ ./kruskal  please input graph type dg(0) or udg(1) :0 please input vexmun : 4 please input arcnum : 5 please input 1th vex(char):a   please input 2th vex(char):b please input 3th vex(char):c please input 4th vex(char):d please input 1th arc v1(char) v2(char) weight(int): a b 1 please input 2th arc v1(char) v2(char) weight(int): a c 3 please input 3th arc v1(char) v2(char) weight(int): a d 4 please input 4th arc v1(char) v2(char) weight(int): b c 2  please input 5th arc v1(char) v2(char) weight(int): c d 3 graph type: direct graph graph vertex number: 4 graph arc number: 5 vertex set:  a	b	c	d	 adjacency matrix: 0	1	3	4 1000	0	2	1000 1000	1000	0	3 1000	1000	1000	0 the result of kruskal: a,b,1 b,c,2 c,d,3

 

 

 

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/606006.html

(0)
上一篇 2021年5月13日
下一篇 2021年5月13日

精彩推荐