Kruskal算法和哈夫曼树和并查集很像。
这样,这四个顶点的图就被连通了,此时由parent[]数组可知,这个图的根顶点是0,因为parent[0]=-1, 其他的都保存的是他们的双亲顶点,如parent[2]=0, 表示顶点2和0是连通的
Kruskal的存储结构:
#include<iostream>
using namespace std;
#define MaxSize 100
typedef struct{
int begin; //起始顶点
int end; //结束顶点
int weight; //这两个顶点之间的代价值
}EdgeType;
typedef struct {
EdgeType edge[MaxSize]; //一个如下图中edge类型的变量
int vertex[MaxSize]; /保存着各个顶点的信息
int vertexNum, arcNum;
}Graph;
思路:
设置一个parent[]数组,用于记录顶点是否已经加入生成树。
对着G.ArcNum条边进行遍历,判断每条边连接的两个顶点是否加入了生成树,若没加入,则加入生成树。
创建图:
void CreatGraph(Graph &G, int n, int e, int arr[])
{
G.vertexNum = n;
G.arcNum = e;
for(int i=0; i<G.vertexNum; i++)
{
G.vertex[i] = arr[i];
}
for(int i=0; i<G.arcNum; i++)
{
int a,b,w;
cin>>a>>b>>w;
G.edge[i].begin = a;
G.edge[i].end = b;
G.edge[i].weight = w;
}
}
int main()
{
int n,e,mincost;
cin>>n>>e;
int arr[n];
for(int i=0; i<n; i++)
{
cin>>arr[i];
}
Graph G;
CreatGraph(G,n,e,arr);
Kruskal(G,mincost);
cout<<"mincost="<<mincost<<endl;
return 0;
}
Kruskal:
有一个parent[]数组,若 i 顶点是根节点的时候,parent[i] =-1 保存的值是-1,若 i 顶点不是根节点,parent[i] = j, 数组保存的是双亲节点,即 顶点 j是i的双亲顶点。
是一个根据weight值从小到大排序的一个数组。
Kruskal的edge数组有三个变量,begin,end, weight分别表示一条边的起始顶点,尾顶点,和这条边的权值。
开始遍历图中的每一条边,当两个顶点根节点不同时,说明来自两个不同的子树,那么就将这两个子树连线,
当树中所有顶点都连通后(也就是num==G.vertexNum-1),即可退出
或者图的所有边都遍历结束,则退出。
最小生成树Kruskal代码:
void Kruskal(Graph &G, int &mincost)
{
mincost=0;
sort_(G); //对edge数组按照weight从小到大的顺序排序, 这样一定是从代价小的边选择。
int parent[MaxSize]; //用于记录是否已经加入生成树和哪些顶点是一组的
//初始化parent[]数组为-1, 这样每个顶点都是独立的,
for(int i=0; i<G.vertexNum; i++)
{
parent[i]=-1;
}
int num=0; //用于记录有多少个顶点加入了生成树,当所有顶点加入生成树后,则退出
//遍历所有的边
for(int i=0; i<G.arcNum; i++)
{
//找到两个顶点的根节点,如果根节点相同,说明这两个顶点是同一组,则不连线
//如果两个跟顶点不同,则这两个顶点没连通,我们要把他们连通
int vex1 = findroot(parent, G.edge[i].begin);
int vex2 = findroot(parent, G.edge[i].end);
if(vex1 != vex2) //说明两个顶点是不同的两个子树上, 现在把这两个子树连接起来
{
cout<<" ( "<<G.edge[i].begin<<", "<<G.edge[i].end<<" )"<<G.edge[i].weight<<endl;
mincost += G.edge[i].weight;
parent[vex1]=vex2;
num++;
if(num==G.vertexNum-1) //如果所有顶点都加入了生成树,则退出
{
return;
}
}
}
}
找到顶点的根节点 和sort函数,对数组按照weight从小到大排序
int findRoot(int parent[], int v){
int t = v;
while(parent[t]>-1;){
t = parent[t]; //因为parent[t]中存储的就是双亲的位置,
}
return t;
}
void sort_(Graph &G) //sort别忘了引用的方式修改变量G,
{
for(int i=0; i<G.arcNum-1; i++)
{
for(int j=1; j<G.arcNum-i; j++)
{
if(G.edge[j-1].weight > G.edge[j].weight)
{
EdgeType tmp = G.edge[j-1];
G.edge[j-1]=G.edge[j];
G.edge[j]=tmp;
}
}
}
}
练习:
6 10
0 1 2 3 4 5
0 1 6
0 2 1
0 3 5
1 2 5
1 4 3
2 3 5
2 4 6
2 5 4
3 5 2
4 5 6
结果: