数据结构-chap7 (3)最小生成树
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
v4
深度和广度优先生成树
采用DFS遍历图所得到的生成树称为深度优先生成树,采用 BFS遍历图所得到的生成树称为广度优先生成树 v1
v1
v2 v3 v2 v7 v4 v5 v1 v3 v6 v8 v7
v2 v4 v5
v3
v6
v8
v7
v4
v5
v6
v8
深度优先生成树
广度优先生成树
自测题 1 深度优先(广度优先)生成树
0
1
2
3
4
5
6 V2 3
5 6
V1 1 V3 5
5
V4
2
4 V6
V5
6
v1 v2 v3 v4 v5 v6
4
V1
6 6 1 5 5 3
k 0
1 5 5 6 4
5 3 5 6 4 2 6 2 6
closedge adjvex lowcost
6 V2 3 5
V1 1 V3 6 i 5 4
5 V4 V2 V5 2
V1 1
V1 1 V3 V4 V6 5
{v1} V3 6 V3 4 {v1,v3}
V1 V2 V5 U V-U
{v2,v3, V4,v5,v6} {v2,V4, v5,v6}
1 V3
V4 4 V6 k
6
V5
2
V6 1 3
V1 5 V1 5
7.4 最小生成树
一 图的生成树
二 最小生成树
一、图的生成树
对于一个有n个顶点的无向连通图,它的边数≥n-1条。若从中选择n-1条边,使 得无向图仍然连通,则由n个顶点及这 n-1条边组成的图被称为原无向图的生 成树。
v3
v3
v3
v4 v2 v1
v3
v2
v4
v2 v1v4Fra bibliotekv1 生成树不唯一
v2
v1
如此继续下去, 直到网络中的所有顶点都加入到U 中为止。
例如:
a
18 16
19 14 12
b
7
5
c
3
e
8
g
27
d
f
21
所得生成树权值和 = 14+8+3+5+16+21 = 67
构造过程中,设置了一个辅助数组closedge[],存放从生成树 顶在点集合U内顶点到生成树外顶点集合V-U中各顶点上具有最小 权值的边。
如何实现这个操作过程的算法?
分析 : (1)它主要有两项操作:按条件选择一条边; 将顶点加入到U集合中。 (2)网中的每个顶点不是在U集合中,就是在V-U集合中。
设计一个辅助数组closedge[ ]:记录从集合U到集合V-U具有最小权值的边。
对每个属于V-U集合的顶点,在辅助数组中存在一个相应的分量 closedge[i-1],它包括两个域:
6
V2
V1
5
1
V3
5
V1
V4 V2 V5
V1 V4 V2 V5
3 6
V5
5 4
1
V3 5
V3 5 V3 5
1
V3
1
V3
V4
6
2
V6
4
V6
4
V6
2
k
5
3 1
closedge
adjvex lowcost
adjvex lowcost adjvex Lowcost
i
2
0 0 0
3
V1 5
V6 2 0
4
V3 6
2
3
4
5
v1,v3
v3,v6
v6,v4
1
V3 5
5
5
1 5 5 6 4
k 3 5
5 3 5 6 4 2 6 2 6
closedge adjvex lowcost
i
0
2
V1 0
3
V6
4
V3
0
2 0
6
V3 0
for (i=1; i<n; i++) { //选择其余G.vexnum-1个顶点
2
3
4
5
v1,v3
v3,v6
5
5
1 5 5 6 4
k 2 5
5 3 5 6 4 2 6 2 6
closedge adjvex lowcost
i
0
1
V3 5
2
V1 0
3
V1 V6 5 2
4
V3
0
6
V3 4 0
for (i=1; i<n; i++) { //选择其余G.vexnum-1个顶点
一个域:表示在该顶点与V-U集合中某些顶点构成的边中 权最小的那条边的权值,若该顶点进入U集合,则值为0。 另一个域:表示这条最小权值的边对应的在V-U集合中的顶点下标。
辅助数组closedge[]类型定义如下:
#define MAX_NUM 10 struct { int adjvex; float lowcost; }closedge[MAX_NUM];
i
0
1
V1 6
2
V1 1
3
V1
5 V1
0
5
for (i=1; i<n; i++) { //选择其余G.vexnum-1个顶点
k = minimun(closedge); //求出T的下一个结点:下标为k的顶点 printf(closedge[k].adjvex,G.vexs[k]); 0 1 closedge[k].lowcost=0;//下标为k的顶点加入U中 0 6 for(j=0; j<G.vexnum; j++) if(G.arcs[k][j].adj < closedge[j].lowcost) 1 6 //新顶点加入U后重新选择最小边 2 1 5 closedge[j]={G.vexs[k],G.arcs[k][j].adj }; 3 5 } 4 3 }
整个算法的执行过程可以描述为:
{ 初始化closedge数组的内容;
选择某个顶点k作为生成树的根结点,并将它加入到U集合中;
重复下列操作n-1次: 选择一条满足条件的边; 输出这条边的两个端点;
修改V-U集合中的顶点信息,寻找与U集合中构成最小权值的边。
}
void Mini_SpanTree_PRIM(MGraph G,VertexType u) { //用Prim算法从值为u的顶点出发构造网G的最小生成树T,输出T的各条边 k = LocateVex(G,u); //生成树根结点的下标 for(j=0; j<G.vexnum; ++j) //辅助数组初始化 if(j!=k) closedge[j] = {u, G.arcs[k][j].adj}; //{ adjvex,lowcost} closedge[k].lowcost = 0; //初始,U={ u }
k = minimun(closedge); //求出T的下一个结点:下标为k的顶点 printf(closedge[k].adjvex,G.vexs[k]); 0 1 closedge[k].lowcost=0;//下标为k的顶点加入U中 for(j=0; j<G.vexnum; j++) 0 6 if(G.arcs[k][j].adj < closedge[j].lowcost) 1 6 //新顶点加入U后重新选择最小边 2 1 5 closedge[j]={G.vexs[k],G.arcs[k][j].adj }; 5 3 } 4 3 }
6
V5
1
普里姆(Prim)算法 基本思想:
从连通网络 N = { V, E }中的某一顶点 u0 出发,
选择与它关联的具有最小权值的边 ( u0, v ),
将其顶点加入到生成树顶点集合U中。
以后每一步中,
从一个顶点在 U 中,而另一个顶点不在 U 中的各条边中, 选择权值最小的边(u, v),把它的顶点加入到集合 U 中。
k = minimun(closedge); //求出T的下一个结点:下标为k的顶点 printf(closedge[k].adjvex,G.vexs[k]); 0 1 closedge[k].lowcost=0;//下标为k的顶点加入U中 for(j=0; j<G.vexnum; j++) 0 6 if(G.arcs[k][j].adj < closedge[j].lowcost) 1 6 //新顶点加入U后重新选择最小边 2 1 5 closedge[j]={G.vexs[k],G.arcs[k][j].adj }; 5 3 } 4 3 }
v1 v2 v3 v4 v5 v6 1 0 1 3 2 4 4 2 2 4 ∧ 5 ∧ 5 ∧ 3 4 ∧ 5 ∧
0 0 1
生成森林
当图中包括多个连通分量时,在遍历图时,每个连
通分量是一棵生成树,生成树的不相交集合形成生
成森林。
二、最小生成树
实际问题:假设连通图G的顶点表示城市,边表示连接两个城市之间
{v5} { }
4
普里姆(Prim)算法
详细过程:
设置两个集合,U集合中的元素是在生成树中的结点, V-U集合中的元素是不在生成树中的顶点。 首先,选择一个作为生成树根结点的顶点,并将它放入U集合。 然后,在那些一端顶点在U集合中,而另一端顶点在V-U集合中的边中找一条权 最小的边,并把这条边和那个不在U集合中的顶点加入到生成树中,输出这条 边,将其顶点添加到U集合中;重复这个操作n-1次。
closedge adjvex lowcost
adjvex lowcost
4
V1
6
V3 5
2
5
0
说明:初始状态时,由于U={v1},则到V-U中各顶点的最小边,即为从依附于顶点v1 的各条边中,找到一条权值最小的边(u0,v0)=(1,3)为生成树上的第一条边,将 v0(=v3)并入集合U,再修改辅助数组中的值.先将closedge[2].lowcost改为‘0’, 以示顶点v3已并入U;然后,由于边(v3,v2)上的权值小于closedge[1].lowcost,则 需修改closedge[1]为边(v3,v2)及其权值.同理修改closedge[4]和closedge[5]。
的通信线路。若有n个城市,连接这n个城市最少需n-1条边,则图的生
成树就表示所有可行的通信线路。 最小生成树:n个顶点网络的生成树有n个结点,n-1条分枝。假设 网络中有m条边(m≥n-1),用MST表示许多可能的生成树的集合,每棵
树中n-1条分枝上的权之和用WG(T)表示,则使得
WG(Tmin)=Min{WG(T)| T MST} 的生成树Tmin便是网络的最小生成树。
V3 6 V3 6
5
V3 4
0 0
U
{v1,v3}
{v1,v3,v6} {v1,v3, V6,v4}
V-U
{v2,V4, v5,v6}
{v2,V4, v5} {v2, v5}
6
V2
V1
5
1
V3
5 5 4
1
V3 5 0 0 V4 V2 V5
V1
V1 V4
1
V3
V2
5 1
3 6
V5
6
2
V6
4
V6 V5
对每个viV-U,在closedge中存在一个相应分量closedge[i-1], 它包括两个域:
closedge[i-1].lowcost = Min{cost(u,vi)| u U}, 即存放生成树顶点集合U内顶点到生成树外各顶点V-U 的各边上的当前最小权值; closedge[i-1].adjvex:存储该边依附的在U中的顶点, 即记录生成树顶点集合外V-U各顶点距离集合内U哪个顶点 最近(即权值最小)。
2
3
4
5
v1,v3
5
5
1 5 5 6 4
k 2 0
5 3 5 6 4 2 6 2 6
closedge adjvex lowcost
i
0
1
V1 V3 6 5
2
V1 1 0
3
V1
4
V1 V3 6
0
5
V1 V3 4
for (i=1; i<n; i++) { //选择其余G.vexnum-1个顶点
k = minimun(closedge); //求出T的下一个结点:下标为k的顶点 printf(closedge[k].adjvex,G.vexs[k]); 0 1 closedge[k].lowcost=0;//下标为k的顶点加入U中 for(j=0; j<G.vexnum; j++) 0 6 if(G.arcs[k][j].adj < closedge[j].lowcost) 1 6 //新顶点加入U后重新选择最小边 2 1 5 closedge[j]={G.vexs[k],G.arcs[k][j].adj }; 5 3 } 4 3 }
算法:Prim算法 和Kruskal算法。
构造最小生成树的方法 构造最小生成树的准则:
必须使用且仅使用该网络中的n-1 条边来联结网络中的 n 个顶点; 不能使用产生回路的边; 各边上的权值的总和达到最小。
V1
1 2
V6
V2
V1
1
V6
1
V5
1
1
5 6
V4 V3
V2
1
5 6
V4 V3
3 1
V3
V4
4 2
V6
closedge
adjvex lowcost
i
2
0
0 0
3
0
0 0
4
V3 6
5
0
0 0
U
{v1,v3, V6,v4}
V-U
{v2, v5}
k
1
adjvex lowcost adjvex Lowcost
V2 3
0
{v1,v3, V6,v4,v2} {v1,v3,V6, v4, v2 , v5}