最小生成树——Prim算法和Kruskal算法
一.最小生成树
1.回顾:生成树
连通图的生成树是包含图中全部顶点的一个极小连通子图
解释:全部顶点+必须连通+边最少
·生成树结果可能不唯一
注:顶点数为n,则它的生成树含有 n-1 条边(边最少且连通)。减一条边变为非连通;加一条边产生回路。
2.最小生成树
边的权值之和最小的生成树
性质
(1)通常最小生成树不是唯一的,但图G中各边权值互不相等时,G的最小生成树唯一
(2)若G本身是一棵树时(无向连通图G的边数比顶点数少1),G的最小生成树就是他本身
(3)最小生成树边的权值之和唯一,且为最小
(4)最小生成树的|E|=|V|-1
一个通用的最小生成树算法
GENERIC_MST(G){
T=NULL;
while T未形成一棵生成树;
do 找到一条最小代价边(u,v)并且加入T后不会产生回路;
T=T U (u,v);
}
二.Prim算法(普里姆算法)
1.背景
普里姆算法(Prim算法),该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。
——百度百科
2.概念
Prim 算法:
从某一个顶点开始构建生成树;每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。(结果不唯一)
顺序:学校、P城+矿场+渔村+农场+电站
最小代价:15
结果不唯一,但最小代价相同
3.Prim算法的实现思想
(1)isJoin用来标记各结点是否已加入树,已加入为√,未加入为×
(2)lowCost用来表示当前结点加入最新树的最低代价,∞表示当前树到该顶点之间没有路径
选择最小的lowCost加入树(已有的除外),加入V3,并更新lowCost数组,当前lowCost为各顶点到树(此时树有V0和V3)的最短路径
注:在更新lowCost数组时,只需将新加入结点到未加入树的各顶点的代价/与各顶点当前对应的lowCost数组值进行比较,若更小则替换更新lowCost数组
V2加入(加入V5也可),更新lowCost数组
V5加入,更新lowCost数组
V1加入,更新lowCost数组
V4加入,更新lowCost数组
时间复杂度:
从V0开始,总共需要 n-1 轮处理
每⼀轮处理:循环遍历所有个结点,找到lowCost最低的,且还没加入树的顶点。
再次循环遍历,更新还没加入的各个顶点的lowCost值
故总的时间复杂度为(n-1)*O(2n)=O(n²)=O(|V|²)
适合用于边稠密图
三.Kruskal算法
1.概念
每次选择⼀条权值最小的边,使这条边的两头连通(原本已经连通的就不选),直到所有结点都连通
2.过程
找到最小的边1
树:学校、P城
找到最小的边2
找到最小的边3
找到最小的边4,如P城和矿场
下一个最小的边为4(P城和渔村)
但此时P城和渔村已连通,跳过,继续寻找下一个权值最小且非连通的边5,为农场和P城
完成,最小代价:15
与Prim算法结果相同
3.时间复杂度
每次要选择代价最小的边,故先对边按权值递增排序
边1权值最小,连接V0和V3,检查是否连通(并查集);
查并集:起初不同结点为不同集合(不连通),即V0和V3不连通
连上V0和V3后,变为同一个集合
V2、V5
V1、V4同理
下面连V2、V3,属于不同的集合(不连通),故连接V2、V3
观察V3和V5,此时V3和V5属于同一集合,跳过
以下同理
一共e条边,需要执行e轮
每轮都要通过并查集判断两个顶点是否属于同一集合,时间开销O(log2|E|),故总时间复杂度为O(|E|log2|E|)
适合用于边稀疏图
四.对比总结