算法原理:
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;
}