Kruskal算法(c++实现)

算法原理:

1.将边的权值从小到大排列;

2.构造辅助数组root[n](n为节点个数)

3.按照边的权值从小到大的顺序考察各条边;

4.关键:如何判别被考察边的两个顶点是否位于两个连通分量(用到辅助函数);先将辅助函数各项初始化为-1,如果root[i]为-1;则顶点就为该连通分量的“跟”,对于边(u,v),设v1,v2分别为两个顶点所在的连通分量的根节点;如果v1不等于v2,则u,v必定位于不同的连通分量,然后令root[v2]=v1;实现树的合并。当求顶点v所在连通分量的跟节点只需要沿着v=root[v]不断查找就行,一直循环到root[v]=-1;

5:实现步骤如下:

首先,在初始状态下,对各顶点赋予不同的标记(用颜色区别),如下图所示:

(1)

对所有边按照权值的大小进行排序,按照从小到大的顺序进行判断,首先是(1,3),由于顶点 1 和顶点 3 标记不同,所以可以构成生成树的一部分,遍历所有顶点,将与顶点 3 标记相同的全部更改为顶点 1 的标记,如(2)所示:

其次是(4,6)边,两顶点标记不同,所以可以构成生成树的一部分,更新所有顶点的标记为:

其次是(2,5)边,两顶点标记不同,可以构成生成树的一部分,更新所有顶点的标记为:

继续选择权值最小的边,此时会发现,权值为 5 的边有 3 个,其中(1,4)和(3,4)各自两顶点的标记一样,如果连接会产生回路,所以舍去,而(2,3)标记不一样,可以选择,将所有与顶点 2 标记相同的顶点的标记全部改为同顶点 3 相同的标记:

当选取的边的数量相比与顶点的数量小 1 时,说明最小生成树已经生成。所以最终采用克鲁斯卡尔算法得到的最小生成树为(6)所示。

代码实现(注释在行后边):

# include <iostream>
using namespace std;
struct EdgeType                                     //关于图中边的信息的结构体
{
	int from, to;
	int Weight;
};
struct EdgeGraph                                    //关于整个图中顶点、边的所有信息,需要将前面边的结构体内容导入此结构体
{
	int Vertex[100];                            //顶点数组,假设最大顶点数和边数不超过100
	EdgeType Edge[100];                         //边信息的结构体数组
	int VertexNum, EdgeNum;                     //顶点数、边数
};
void Create(struct EdgeGraph *MyEdgeGraph);         //构造图的函数函数
void WayToAchieve(struct EdgeGraph *MyEdgeGraph);   //算法实现函数
int FindRoot(int Parent[],int v);                   //寻找各连通分量根的函数
void main()
{
	EdgeGraph MyEdgeGraph;
	Create(&MyEdgeGraph);
	WayToAchieve(&MyEdgeGraph);
	system("pause");
	return;
}
void Create(struct EdgeGraph *MyEdgeGraph)
{
	int Vertex, Edge, Weight;
	cout << "请输入无向图的顶点数:" << endl;
	cin >> Vertex;
	cout << "请输入无向图的边数:" << endl;
	cin >> Edge;
	cout << "请依次输入每个边所依附的两个顶点和边的权值:" << endl;
	EdgeType *MyEdge = new EdgeType[Edge];             //申请用户要求数量的边信息结构体数组
	for (int i = 0; i < Edge; i++) {                   //边结构体数组的初始化
		cin >> MyEdge[i].from >> MyEdge[i].to >> MyEdge[i].Weight;
	}
	for (int i = 0; i < Edge; i++) {                   //依据各边的权值进行重新排序
		for (int j = i + 1; j < Edge; j++) {
			if (MyEdge[i].Weight > MyEdge[j].Weight) {
				EdgeType Temp;
				Temp = MyEdge[i];
				MyEdge[i] = MyEdge[j];
				MyEdge[j] = Temp;
			}
		}
	}
	(*MyEdgeGraph).VertexNum = Vertex;            
	(*MyEdgeGraph).EdgeNum = Edge;
	for (int i = 0; i < Edge; i++) {
		(*MyEdgeGraph).Edge[i] = MyEdge[i];                //将边的信息结构体导入图的信息结构体
	}
	for (int i = 0; i < Vertex; i++) {
		(*MyEdgeGraph).Vertex[i] = i;                     //初始化图结构体的顶点数组
	}
}
void WayToAchieve(struct EdgeGraph *MyEdgeGraph)
{
	int num = 0, i = 0,v1,v2;
	int *root = new int[(*MyEdgeGraph).VertexNum];        //创建辅助函数并初始化
	for (int i = 0; i < (*MyEdgeGraph).VertexNum; i++) {
		root[i] = -1;
	}
	for (num = 0, i = 0; i < (*MyEdgeGraph).EdgeNum; i++) {      //依次对每个边进行遍历,num记录输出边的个数
		v1 = FindRoot(root,(*MyEdgeGraph).Edge[i].from);    //分别寻找v1,v2所在连通分量的根
		v2 = FindRoot(root, (*MyEdgeGraph).Edge[i].to);
		if (v1 != v2) {                                     //如果所在不同的连通分量就合并
			cout << "("<<(*MyEdgeGraph).Edge[i].from<<(*MyEdgeGraph).Edge[i].to<<")" << endl;
			root[v2] = v1;                                 //合并
			num++;                                         //记录选择边的个数
			if (num == (*MyEdgeGraph).VertexNum - 1) {     //如果选择的边次数等于顶点数-1则证明最小树已经生成,结束函数调用
				return;
			}
		}
	}
}
int FindRoot(int Parent[], int v)
{
	int v1 = v;
	while (Parent[v1] > -1) {         //不停循环找根
		v1 = Parent[v1];
	}
	return v1;
}
发布了37 篇原创文章 · 获赞 12 · 访问量 9269

猜你喜欢

转载自blog.csdn.net/weixin_43265881/article/details/90216645