最小生成树:Kruskal算法
Kruskal算法的思想就是站在上帝视角,把整个图中权值最短的边一个个挑出来.
顶点数组
辅助数组(此数组旨在避免在构造最小生成树时产生回路)
V
e
x
s
e
t
[
i
]
Vexset[i]
Vexset[i] :标识各个顶点所属的连通分量.表示该顶点所在的连通分量
V
e
x
s
e
t
[
i
]
=
i
Vexset[i]=i
Vexset[i]=i :开始时每个顶点都自成一个连通分量 辅助数组的初始值:
V
e
x
s
e
t
[
i
]
=
{
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
}
Vexset[i]=\{0,1,2,3,4,5,6,7,8\}
Vexset[i]={0,1,2,3,4,5,6,7,8}
边集数组
E
d
g
e
[
i
]
Edge[i]
Edge[i]:存储边的顶点下标和权值
typedef struct{
VerTexType begin;
VerTexType end;
ArcType weight;
}Edge[arcnum];
将邻接矩阵通过程序转化为边集数组,并按权值从小到大排序
找出整个图中权值最小的边
(
V
4
,
V
7
)
(V_4,V_7)
(V4?,V7?)
至此连通分量有:
V
4
V_4
V4? ,
V
7
V_7
V7? 构成的一个连通分量 其余每个顶点都依旧各自自成一个连通分量 找出目前权值最小的边
(
V
2
,
V
8
)
(V_2,V_8)
(V2?,V8?)
至此连通分量有:
V
2
V_2
V2? ,
V
8
V_8
V8? 构成的一个连通分量
V
4
V_4
V4? ,
V
7
V_7
V7? 构成的一个连通分量 其余每个顶点都依旧各自自成一个连通分量 找出目前权值最小的边
(
V
0
,
V
1
)
(V_0,V_1)
(V0?,V1?)
至此连通分量有:
V
0
V_0
V0? ,
V
1
V_1
V1? 构成的一个连通分量
V
2
V_2
V2? ,
V
8
V_8
V8? 构成的一个连通分量
V
4
V_4
V4? ,
V
7
V_7
V7? 构成的一个连通分量 其余每个顶点都依旧各自自成一个连通分量 找出目前权值最小的边
(
V
0
,
V
5
)
(V_0,V_5)
(V0?,V5?)
V
0
V_0
V0? ,
V
1
V_1
V1? 构成一个连通分量
V
0
V_0
V0? ,
V
5
V_5
V5? 构成一个连通分量 因为边
(
V
0
,
V
1
)
(V_0,V_1)
(V0?,V1?) 和 边
(
V
0
,
V
5
)
(V_0,V_5)
(V0?,V5?) 中都有
V
0
V_0
V0? 所以两个连通分量: 边
(
V
0
,
V
1
)
(V_0,V_1)
(V0?,V1?) 和 边
(
V
0
,
V
5
)
(V_0,V_5)
(V0?,V5?)合并为一个连通分量
至此连通分量有:
V
0
V_0
V0?
V
1
V_1
V1?
V
5
V_5
V5? 构成的一个连通分量
V
2
V_2
V2? ,
V
8
V_8
V8? 构成的一个连通分量
V
4
V_4
V4? ,
V
7
V_7
V7? 构成的一个连通分量 其余每个顶点都依旧各自自成一个连通分量 找出目前权值最小的边
(
V
1
,
V
8
)
(V_1,V_8)
(V1?,V8?)
V
0
V_0
V0?,
V
1
V_1
V1?,
V
5
V_5
V5? 构成一个连通分量
V
1
V_1
V1? ,
V
8
V_8
V8? 构成一个连通分量
V
2
V_2
V2? ,
V
8
V_8
V8? 构成一个连通分量
因为连通分量
V
0
,
V
1
,
V
5
V_0,V_1,V_5
V0?,V1?,V5? 和连通分量
V
1
,
V
8
V_1,V_8
V1?,V8? 之间都有
V
1
V_1
V1? 因为连通分量
V
1
,
V
8
V_1,V_8
V1?,V8? 和连通分量
V
2
,
V
8
V_2,V_8
V2?,V8? 之间都有
V
8
V_8
V8? 以上所有连通分量合并为一个连通分量
V
0
,
V
1
,
V
5
,
V
8
,
V
2
V_0,V_1,V_5,V_8,V_2
V0?,V1?,V5?,V8?,V2?
至此连通分量有:
V
0
,
V
1
,
V
5
,
V
8
,
V
2
V_0,V_1,V_5,V_8,V_2
V0?,V1?,V5?,V8?,V2? 构成的一个连通分量
V
4
V_4
V4? ,
V
7
V_7
V7? 构成的一个连通分量 其余每个顶点都依旧各自自成一个连通分量 找出目前权值最小的边
(
V
3
,
V
7
)
(V_3,V_7)
(V3?,V7?)
V
4
V_4
V4? ,
V
7
V_7
V7? 构成一个连通分量
V
3
V_3
V3? ,
V
7
V_7
V7? 构成一个连通分量 上述两个连通分量中都有
V
7
V_7
V7? 所以将这两个连通分量合并为一个连通分量
V
3
,
V
4
,
V
7
V_3,V_4,V_7
V3?,V4?,V7?
至此连通分量有:
V
0
,
V
1
,
V
5
,
V
8
,
V
2
V_0,V_1,V_5,V_8,V_2
V0?,V1?,V5?,V8?,V2? 构成的一个连通分量
V
3
V_3
V3?,
V
4
V_4
V4?,
V
7
V_7
V7? 构成的一个连通分量 其余每个顶点都依旧各自自成一个连通分量 找出目前权值最小的边
(
V
1
,
V
6
)
(V_1,V_6)
(V1?,V6?)
V
0
,
V
1
,
V
5
,
V
8
,
V
2
V_0,V_1,V_5,V_8,V_2
V0?,V1?,V5?,V8?,V2? 构成一个连通分量
V
1
,
V
6
V_1,V_6
V1?,V6? 构成一个连通分量 以上两个连通分量中都有
V
1
V_1
V1? 所以这两个连通分量合并成一个连通分量
V
0
,
V
1
,
V
5
,
V
8
,
V
2
,
V
6
V_0,V_1,V_5,V_8,V_2,V_6
V0?,V1?,V5?,V8?,V2?,V6?
至此连通分量有:
V
0
,
V
1
,
V
5
,
V
8
,
V
2
,
V
6
V_0,V_1,V_5,V_8,V_2,V_6
V0?,V1?,V5?,V8?,V2?,V6? 构成的一个连通分量
V
3
V_3
V3?,
V
4
V_4
V4?,
V
7
V_7
V7? 构成的一个连通分量
找出目前权值最小的边
(
V
6
,
V
7
)
(V_6,V_7)
(V6?,V7?)
V
6
,
V
7
V_6,V_7
V6?,V7? 构成一个连通分量
V
0
,
V
1
,
V
5
,
V
8
,
V
2
,
V
6
V_0,V_1,V_5,V_8,V_2,V_6
V0?,V1?,V5?,V8?,V2?,V6? 构成一个连通分量
V
3
V_3
V3?,
V
4
V_4
V4?,
V
7
V_7
V7? 构成一个连通分量 以上三个连通分量由于
V
6
,
V
7
V_6,V_7
V6?,V7? 而合并成一个连通分量
V
0
,
V
1
,
V
5
,
V
8
,
V
2
,
V
6
,
V
7
,
V
3
,
V
4
V_0,V_1,V_5,V_8,V_2,V_6,V_7,V_3,V_4
V0?,V1?,V5?,V8?,V2?,V6?,V7?,V3?,V4?
至此连通分量有:
V
0
,
V
1
,
V
5
,
V
8
,
V
2
,
V
6
,
V
7
,
V
3
,
V
4
V_0,V_1,V_5,V_8,V_2,V_6,V_7,V_3,V_4
V0?,V1?,V5?,V8?,V2?,V6?,V7?,V3?,V4?
至此最小生成树构造完成
《数据结构C语言版》内的Kruskal算法描述
void MiniSpanTree_Kruskal(AMGraph G){
Sort(Edge);
for(i=0; i<G.vexnum; ++i)
Vexset[i]=i;
for(i=0; i<G.arcnum; ++i){
v1=LocateVex(G,Edge[i].begin);
v2=LocateVex(G,Edge[i].end);
vs1=Vexset[v1];
vs2=Vexset[v2];
if(vs1 != vs2){
cout << Edge[i].begin << Edge[i].end;
for(j=0; j<G.vexnum; ++j)
if(Vexset[j] == vs2)
Vexset[j]=vs1;
}
}
}
《大话数据结构》内的Kruskal算法描述
void MiniSpanTree_Kruskal(MGraph){
int i,n,m;
Edge edges[MAXEDGE];
int parent[MAXVEX];
Sort(edges);
for(i=0; i<G.numVertiexes; i++)
parent[i]=0;
for(i=0; i<G.numEdges; i++){
n = Find(parent,edges[i].begin);
m = Find(parent,edges[i].end);
if(n != m){
parent[n]=m;
printf("(%d,%d) %d\n", edges[i].begin,edges[i].end,edges[i].weight);
}
}
}
int Find(int *parent, int f){
while(parent[f] > 0){
f = parent[f];
}
return f;
}
|