图之最小生成树Kruskal方法c++实现

克鲁斯卡尔算法

克鲁斯卡尔算法的基本思想是以边为主导地位,始终选择当前可用(所选的边不能构成回路)的最小权植边。所以Kruskal算法的第一步是给所有的边按照从小到大的顺序排序。这一步可以直接使用库函数qsort或者sort。接下来从小到大依次考察每一条边(u,v)。

具体实现过程如下:

<1> 设一个有n个顶点的连通网络为G(V,E),最初先构造一个只有n个顶点,没有边的非连通图T={V,空},图中每个顶点自成一格连通分量。

<2> 在E中选择一条具有最小权植的边时,若该边的两个顶点落在不同的连通分量上,则将此边加入到T中;否则,即这条边的两个顶点落到同一连通分量      上,则将此边舍去(此后永不选用这条边),重新选择一条权植最小的边。

<3> 如此重复下去,直到所有顶点在同一连通分量上为止。

其实克鲁斯卡尔算法可以理解为贪心的思想:去找两个顶点去组合成一条权值最小的边。且加入这条边后不能生成回环。这样一直重复到所有顶点都已经有连接边。

#include <bits/stdc++.h>
#include <Time.h>
using namespace std;
/**
	定义数据结构体 
*/ 
const int M=100; 
typedef char Elemtype;
typedef int  ElemInt;
typedef struct Graph{
	int n;		//顶点 
	int e;		//边 
	//顶点存储	
	ElemInt  vex[M];
	//边存储 
	ElemInt  edges[M][M];
}Graph; 
/**
	图中边的数据结构定义 
*/ 
typedef struct{
	int u;		//起点 
	int v;		//终点 
	int w;		//权值 
}Edge; 
/**
	查找顶点边在数组中的位置 
*/ 
int search(ElemInt vex[],ElemInt point){
	int i=0;
	while(i<M){
		if(vex[i]==point) {
			return i;
		}
		i++; 
	}
	return -1;
}
/**
	(无向图)邻接矩阵的创建 
*/ 
void CreateGraph(Graph &G){
	int l,r;
	printf("请输入顶点和边的个数\n");
	cin>>G.n>>G.e;
	printf("请输入%d条顶点\n",G.n);
	for(int i=0;i<G.n;i++)
		cin>>G.vex[i];
	//初始化矩阵(初始值) 
	for(int i=0;i<G.n;i++)
		for(int j=0;j<G.n;j++)
			if(i==j) 
				G.edges[i][j]=0;			//对角线 
			else
				G.edges[i][j]=32767;
	printf("请输入%d条边的起始和终点位置\n",G.e);
	for(int i=0;i<G.e;i++){
		int lpoint,rpoint,power;
		printf("请输入第%d条边的信息(起始点 终点 权值)\n",i+1);
		cin>>lpoint>>rpoint>>power;		//输入边的信息和权值 
		l=search(G.vex,lpoint);
		r=search(G.vex,rpoint);
		G.edges[l][r]=power;			//l--->r
		G.edges[r][l]=power;			//r--->l
	}
}
 /**
	排序算法
	从小到大	
*/
void Sort(Edge E[],int e){
	int i,j;
	for(i=0;i<e-1;i++)
		for(int j=0;j<e-i-1;j++){
			if(E[j].w>E[j+1].w){
				Edge tmp=E[j];
				E[j]=E[j+1];
				E[j+1]=tmp;
			}
		}
}
/**
	Kruskal算法求解最小生成树过程 
*/
void Kruskal_MinTree(Graph *G){
	int i,j,u1,v1,sn1,sn2,k;
	int vset[M];						//存放下标对应的顶点所属的连通子图编号 
	Edge E[M];							//存放G中的所有边 
	k=0;
	//将图转换为边集数组
	for(i=0;i<G->n;i++){
		for(j=0;j<i+1;j++){
			//遍历邻接矩阵,并将存在的权值存入边集数组E[]
			if(G->edges[i][j]!=0&&G->edges[i][j]!=32767){
				E[k].u=i;
				E[k].v=j;
				E[k].w=G->edges[i][j];
				k++; 
			} 
		}
	}
	//排序
	Sort(E,k);					//权值升序 
	for(i=0;i<G->n;i++)				//初始化vset[]数组,每个顶点相当于一个连通子图 
		vset[i]=i;
	k=1;						//记录已加入生成树中边的数目 
	j=0;						//E中边的下标,从0开始 
	//寻找合适的边
	while(k<G->n){
		u1=E[j].u;
		v1=E[j].v;
		sn1=vset[u1];				//分别得到一条边两个顶点所属的集合编号 
		sn2=vset[v1];
		if(sn1!=sn2){
			//两个顶点属于不同集合,该边可以作为最小生成树的一条边
			printf("(%d,%d):%d\n",u1,v1,E[j].w);
			k++;				//边计数加1 
			for(i=0;i<G->n;i++){
				if(vset[i]==sn2)	//统一两个集合的编号 
					vset[i]=sn1;
			}
		}
		j++;					//扫描下一条边 
	}
	//cout<<"j:"<<j<<"k:"<<k<<endl;		//j从0开始,k从1开始 
}
int main(){
	Graph G;
	CreateGraph(G);				//创建矩阵 
	Kruskal_MinTree(&G);		        //Kruskal算法生成最小生成树 
	return 0;
}


 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值