算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)

文章目录

  • 最小生成树
    • 1.普里姆算法(Prim)
    • 2.克鲁斯卡尔算法(Kruskal)

最小生成树

定义:构造连通网的最小代价生成树

下面两种算法不能处理有向图,克鲁斯卡尔算法在边数少时效率高(适用与稀疏图),普里姆算法对于稠密图效率好一些。

1.普里姆算法(Prim)

(1) 算法思路
从连通网(带权连通图)的任意顶点A开始,将该顶点放入集合V中,然后从与A相连的顶点中找到一个顶点B,使得边的权值最小,将B也放入集合V中,边(A,B)就是最小生成树的一条边。接着再从顶点中找到顶点C使得C到集合V的边权值最小(即到A或B的权值最小)。按照这种步骤继续下去,直到所有的顶点都被访问过。

核心思想:MST中的顶点与非MST中顶点之间的边权重更新(由于每次递归后,总有新的顶点加入MST,此时MST顶点与非MST顶点的边权值可能会有更小值的存在,所以lowcost[i]需要更新)(必须是直连,否则权重为∞)

(2)举例说明
算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第1张图片
设置两个数组:

  • lowcost[i]: 表示以i为终点的边的最小值(当lowcost[i]=0时,说明顶点i加入了最小生成树)
  • mst[i]: 表示对应lowcost[i]的起点(说明边(mst[i],i)是最小生成树的一条边,mst[i]=a表示起点i加入最小生成树

(3)算法步骤

  1. 首先选则V0为起始顶点,则两个数组分别如下(mst[i]全为0是因为默认起点为V0),此时MST中的顶点有{V0}。
lowcost[1] = 10 lowcost[2] = ∞ lowcost[3] = ∞ lowcost[4] = ∞ lowcost[5] = 11 lowcost[6] = ∞ lowcost[7] = ∞ lowcost[8] = ∞
mst[1] = 0 mst[2] = 0 mst[3] = 0 mst[4] = 0 mst[5] = 0 mst[6] = 0 mst[7] = 0 mst[8] = 0
  1. 显然,在所有lowcost[i]中,i = 1时边的权重最小为10(边权重为0的不计),所以V1加入MST。更新后的两个数组如下。此时MST中的顶点有{V0、V1},更新MST中的所有顶点到非MST中的顶点的边权重。(此时由于V1加入了MST,所以MST到V8的边权重不再是∞,而是12,所以lowcost[8] = 12,而且这个12是从V1到V8,所以mst[8] = 1。数组其他数值的改变同理)

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第2张图片

lowcost[1] = 0 lowcost[2] = 18 lowcost[3] = ∞ lowcost[4] = ∞ lowcost[5] = 11 lowcost[6] = 16 lowcost[7] = ∞ lowcost[8] = 12
mst[1] = 0 mst[2] = 1 mst[3] = 0 mst[4] = 0 mst[5] = 0 mst[6] = 1 mst[7] = 0 mst[8] = 1
  1. 此时,在更新后的lowcost[i]中,i = 5时的边权重最小,所以将V5,此时的MST顶点集合为{V0、V1、V5}.再用这个新的MST继续更新这两个数组。(此时,由于MST中的V5到非MST中的V4的边权重为26,比之前的∞小,故lowcost[4] = 26,mst[4] = 5。数组其他数值的改变同理)

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第3张图片

lowcost[1] = 0 lowcost[2] = 18 lowcost[3] = ∞ lowcost[4] = 26 lowcost[5] = 0 lowcost[6] = 16 lowcost[7] = ∞ lowcost[8] = 12
mst[1] = 0 mst[2] = 1 mst[3] = 0 mst[4] = 5 mst[5] = 0 mst[6] = 1 mst[7] = 0 mst[8] = 1
  1. 此时,在更新后的lowcost[i]中(即3得到的新数组),i = 8时的边权重最小,所以将V8,此时的MST顶点集合为{V0、V1、V5、V8}.再用这个新的MST继续更新这两个数组。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第4张图片

lowcost[1] = 0 lowcost[2] = 8 lowcost[3] = 21 lowcost[4] = 26 lowcost[5] = 0 lowcost[6] = 16 lowcost[7] = ∞ lowcost[8] = 0
mst[1] = 0 mst[2] = 8 mst[3] = 8 mst[4] = 5 mst[5] = 0 mst[6] = 1 mst[7] = 0 mst[8] = 1
  1. 此时,在更新后的lowcost[i]中(即4得到的新数组),i = 2时的边权重最小,所以将V2,此时的MST顶点集合为{V0、V1、V5、V8、V2}.再用这个新的MST继续更新这两个数组。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第5张图片

lowcost[1] = 0 lowcost[2] = 0 lowcost[3] = 21 lowcost[4] = 26 lowcost[5] = 0 lowcost[6] = 16 lowcost[7] = ∞ lowcost[8] = 0
mst[1] = 0 mst[2] = 8 mst[3] = 0 mst[4] = 5 mst[5] = 0 mst[6] = 1 mst[7] = 0 mst[8] = 1
  1. 此时,在更新后的lowcost[i]中(即5得到的新数组),i = 6时的边权重最小,所以将V6,此时的MST顶点集合为{V0、V1、V5、V8、V2、V6}.再用这个新的MST继续更新这两个数组。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第6张图片

lowcost[1] = 0 lowcost[2] = 0 lowcost[3] = 21 lowcost[4] = 26 lowcost[5] = 0 lowcost[6] = 0 lowcost[7] = 19 lowcost[8] = 0
mst[1] = 0 mst[2] = 8 mst[3] = 0 mst[4] = 5 mst[5] = 0 mst[6] = 1 mst[7] = 0 mst[8] = 1
  1. 此时,在更新后的lowcost[i]中(即6得到的新数组),i = 7时的边权重最小,所以将V7,此时的MST顶点集合为{V0、V1、V5、V8、V2、V6、V7}.再用这个新的MST继续更新这两个数组。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第7张图片

lowcost[1] = 0 lowcost[2] = 0 lowcost[3] = 16 lowcost[4] = 7 lowcost[5] = 0 lowcost[6] = 0 lowcost[7] = 0 lowcost[8] = 0
mst[1] = 0 mst[2] = 8 mst[3] = 7 mst[4] = 7 mst[5] = 0 mst[6] = 7 mst[7] = 6 mst[8] = 1
  1. 此时,在更新后的lowcost[i]中(即7得到的新数组),i = 4时的边权重最小,所以将V4,此时的MST顶点集合为{V0、V1、V5、V8、V2、V6、V7、V4}.再用这个新的MST继续更新这两个数组。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第8张图片

lowcost[1] = 0 lowcost[2] = 0 lowcost[3] = 16 lowcost[4] = 0 lowcost[5] = 0 lowcost[6] = 0 lowcost[7] = 0 lowcost[8] = 0
mst[1] = 0 mst[2] = 8 mst[3] = 7 mst[4] = 7 mst[5] = 0 mst[6] = 1 mst[7] = 6 mst[8] = 1
  1. 此时,在更新后的lowcost[i]中(即8得到的新数组),i = 3时的边权重最小,所以将V3,此时的MST顶点集合为{V0、V1、V5、V8、V2、V6、V7、V4、V3}.此时,所有的顶点全部进入MST,说明算法结束。此时的两个数组更新为

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第9张图片

lowcost[1] = 0 lowcost[2] = 0 lowcost[3] = 0 lowcost[4] = 0 lowcost[5] = 0 lowcost[6] = 0 lowcost[7] = 0 lowcost[8] = 0
mst[1] = 0 mst[2] = 8 mst[3] = 7 mst[4] = 7 mst[5] = 0 mst[6] = 1 mst[7] = 6 mst[8] = 1

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

(1)算法思路
Prim算法的MST是顶点的集合,Kruskal算法的MST是边的集合。首先按权重从小到大排序(权重相等,先后无所谓),将升序排列的边都对应到数组edges[i]中,先将权重最小的边edges[0]放入MST集合中,然后依次再往MST中放入edges[i],如果要放入的edges[n]会与现有的MST中的边形成环路,则edges[n]不放入MST,就这样一直循环,直到MST集合中的边包含了所有n个顶点,并且MST边的个数为n-1(即所有顶点都连接到了一起)。

核心思想:每次要试图加入MST中的边不能与MST中的边形成环路

(2)举例说明
将邻接矩阵转化为数组,并对它们按权值从小到大排序。(如果遇到权值相等的没关系,先后无所谓)
算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第10张图片

(3)算法步骤

  1. 设置一个数组edges[i],若edges[i]属于MST集合,则edges[i] = 1(相当于放入集合成功),否则为0。第一步先试图将edges[0]放入MST,无环路,放入成功(更新数组如下),此时MST集合为{edges[0]},包含的顶点集合为{V4、V7}。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第11张图片

edges[0] = 1 edges[1] = 0 edges[2] = 0 edges[3] = 0 edges[4] = 0 edges[5] = 0 edges[6] = 0 edges[7] = 0 edges[8] = 0 edges[9] = 0 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0
  1. 再试图将edges[1]放入MST,无环路,放入成功(更新数组如下),此时MST集合为{edges[0]、edges[1]},包含的顶点集合为{V4、V7、V2、V8}。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第12张图片

edges[0] = 1 edges[1] = 1 edges[2] = 0 edges[3] = 0 edges[4] = 0 edges[5] = 0 edges[6] = 0 edges[7] = 0 edges[8] = 0 edges[9] = 0 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0
  1. 再试图将edges[2]放入MST,无环路,放入成功(更新数组如下),此时MST集合为{edges[0]、edges[1]、edges[2]},包含的顶点集合为{V4、V7、V2、V8、V0、V1}。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第13张图片

edges[0] = 1 edges[1] = 1 edges[2] = 1 edges[3] = 0 edges[4] = 0 edges[5] = 0 edges[6] = 0 edges[7] = 0 edges[8] = 0 edges[9] = 0 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0
  1. 再试图将edges[3]放入MST,无环路,放入成功(更新数组如下),此时MST集合为{edges[0]、edges[1]、edges[2]、edges[3]},包含的顶点集合为{V4、V7、V2、V8、V0、V1、V5}。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第14张图片

edges[0] = 1 edges[1] = 1 edges[2] = 1 edges[3] = 1 edges[4] = 0 edges[5] = 0 edges[6] = 0 edges[7] = 0 edges[8] = 0 edges[9] = 0 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0
  1. 再试图将edges[4]放入MST,无环路,放入成功(更新数组如下),此时MST集合为{edges[0]、edges[1]、edges[2]、edges[3]、edges[4]},包含的顶点集合为{V4、V7、V2、V8、V0、V1、V5、V8}。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第15张图片

edges[0] = 1 edges[1] = 1 edges[2] = 1 edges[3] = 1 edges[4] = 1 edges[5] = 0 edges[6] = 0 edges[7] = 0 edges[8] = 0 edges[9] = 0 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0
  1. 再试图将edges[5]放入MST,无环路,放入成功(更新数组如下),此时MST集合为{edges[0]、edges[1]、edges[2]、edges[3]、edges[4]、edges[5]},包含的顶点集合为{V4、V7、V2、V8、V0、V1、V5、V3}。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第16张图片

edges[0] = 1 edges[1] = 1 edges[2] = 1 edges[3] = 1 edges[4] = 1 edges[5] = 1 edges[6] = 0 edges[7] = 0 edges[8] = 0 edges[9] = 0 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0
  1. 再试图将edges[6]放入MST,无环路,放入成功(更新数组如下),此时MST集合为{edges[0]、edges[1]、edges[2]、edges[3]、edges[4]、edges[5]、edges[6]},包含的顶点集合为{V4、V7、V2、V8、V0、V1、V5、V3、V6}。

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第17张图片

edges[0] = 1 edges[1] = 1 edges[2] = 1 edges[3] = 1 edges[4] = 1 edges[5] = 1 edges[6] = 1 edges[7] = 0 edges[8] = 0 edges[9] = 0 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0
  1. 再试图将edges[7]放入MST,此时edges[7]与MST集合中的边形成了环路,故放入失败(数组不更新),此时MST集合为{edges[0]、edges[1]、edges[2]、edges[3]、edges[4]、edges[5]、edges[6]},包含的顶点集合为{V4、V7、V2、V8、V0、V1、V5、V3、V6}。

矫正:下图中V3和V6的边不加粗
算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第18张图片

edges[0] = 1 edges[1] = 1 edges[2] = 1 edges[3] = 1 edges[4] = 1 edges[5] = 1 edges[6] = 1 edges[7] = 0 edges[8] = 0 edges[9] = 0 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0
  1. 再试图将edges[8]放入MST,此时edges[8]与MST集合中的边形成了环路,故放入失败(数组不更新),此时MST集合为{edges[0]、edges[1]、edges[2]、edges[3]、edges[4]、edges[5]、edges[6]},包含的顶点集合为{V4、V7、V2、V8、V0、V1、V5、V3、V6}。

矫正:下图中V3和V6的边不加粗

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第19张图片

edges[0] = 1 edges[1] = 1 edges[2] = 1 edges[3] = 1 edges[4] = 1 edges[5] = 1 edges[6] = 1 edges[7] = 0 edges[8] = 0 edges[9] = 0 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0
  1. 再试图将edges[9]放入MST,无环路,放入成功(更新数组如下),此时MST集合为{edges[0]、edges[1]、edges[2]、edges[3]、edges[4]、edges[5]、edges[6]、edges[9]},包含的顶点集合为{V4、V7、V2、V8、V0、V1、V5、V3、V6}。(此时MST中边的个数为 9 - 1 = 8,说明算法结束)

算法与数据结构学习笔记(5):图的最小生成树(普里姆算法和克鲁斯卡尔算法)_第20张图片

edges[0] = 1 edges[1] = 1 edges[2] = 1 edges[3] = 1 edges[4] = 1 edges[5] = 1 edges[6] = 1 edges[7] = 0 edges[8] = 0 edges[9] = 1 edges[10] = 0 edges[11] = 0 edges[12] = 0 edges[13] = 0 edges[14] = 0

你可能感兴趣的:(#,算法与数据结构基础)