考研数据结构 第6章图|图的应用一、最小生成树

671 阅读3分钟

这是我参与8月更文挑战的第24天,活动详情查看:8月更文挑战

图的应用

一、最小生成树

一个连通图的生成树是图的极小连通子图,它包含图中所有顶点和尽可能少的边,且一个连通图可能有多个生成树 对一个带权的连通有向图G,生成树不同,每棵树的权(树中所有边上的权值之和)也可能不同,对于树的权最小的那棵生成树称为图G的最小生 成树由定义知最小生成树的性质:

  • 最小生成树不一定唯一,树形也不一定唯一,但当图G中的各边权值 互不相等时,图G的最小生成树唯一
  • 最小生成树的边的权值之和总是唯一的,而且是最小的
  • 最小生成树的边数为顶点数减1 已知一个图G如何构造它的最小生成树?

两种方法 : 普里姆(Prim)算法
库鲁斯卡尔(Kruskal)算法 一、最小生成树

1.普里姆(Prim)算法

算法步骤:

①初始化:向空树T={𝑉𝑇,𝐸𝑇}中添加图G=(V,E)中的任一顶点𝑢0,使𝑉𝑇={𝑢0},𝐸𝑇=∅

②循环(重复下列操作直到𝑉𝑇=V):从图G中选择满足{(u,v)|u∈ 𝑉𝑇,v∈ 𝑉 −𝑉𝑇} 且具有最小权值的边(u,v),并置𝑉𝑇=𝑉𝑇 ∪ {𝑣} ,𝐸𝑇 = 𝐸𝑇 ∪{(𝑢,𝑣)}

image.png

Prim算法的伪代码实现

void  Prim(G,T){
T= ∅; //初始化空树
U={w};                      //添加任一顶点w
while((V-U)!= ∅){ //树中不含全部顶点时继续循环
T=T∪{(u,v)};       //设(u,v)是权值最小的满足条件的边,边归入树 U=U∪{v};            //顶点归入树
}
}

注意:

  • Prim算法的时间复杂度为O(|V|2),不依赖于|E|
  • 因此该算法适合求解顶点少但边稠密的图的最小生成树
  • Prim算法是基于贪心策略,每次选取都是当前子问题的最优解,局部最优整体构成全局最优
  • 本算法考研会主要考察相关算法思想和手工模拟算法的步骤,一般不会考实际代码实现

2.克鲁斯卡尔(Kruskal)算法

算法步骤:

①初始化:𝑉𝑇=V,𝐸𝑇 = ∅。即每个顶点构成一棵独立的树,T此时是一个含有 |V|个顶点的森林

②循环(重复下列操作直到T是一棵树):按G的边的权值递增顺序依次从 E-𝐸𝑇中选择一条边,如果这条边加入后不构成回路,则将其加入𝐸𝑇,否则舍 弃,直到𝐸𝑇中含有n-1条边

image.png

Kruskal算法的伪代码实现

void  Kruskal(V,T){
T= 𝑉; //初始化树T,仅含顶点
numS=n;                      //连通分量数 while(numS>1){       //连通分量大于1继续循环
从E中取出权值最小的边(v,u); 
if(v和u属于T中不同的连通分量){
T=T∪{(v,u)};            //将此边加入生成树中 numS--;                    //连通分量数减1
}
}

注意:

  • Kruskal算法中,可采用小顶堆(也叫小根堆)来存放边的集合,则每次选择最小权值的边只需O(log|E|)的时间,这种取最小权值的边需要执行 |E|-1次,故总的时间复杂度为O(|E|log|E|)
  • 因此该算法适合求解顶点多但边稀疏的图的最小生成树
  • Kruskal算法是基于贪心策略,每次选取都是当前子问题的最优解,局部最优整体构成全局最优
  • 本算法考研会主要考察相关算法思想和手工模拟算法的步骤,一般不会考实际代码实现