最小生成树(kruskal算法和Prim算法)

本文详细解析了Prim和Kruskal两种最小生成树算法的核心思想与实现细节,介绍了如何通过这两种算法来寻找图中所有顶点的最短连接路径。

1.问题

最小生成树:一个有 n 个结点连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。

2.解析

prim算法:
**核心思想:**让一颗小树长大。
①随机选择一点v加入V(初始时为空),并设一变量ans记录已选中的权值和
②找到图中权值最小的边<v1,v2>,要求v1存在V中、v2不存在V中
③将v2加入V中,ans += 边<v1,v2>的权重
重复②③步骤
遇到的难点:
for(已选的点){
for(未选的点){
找出权值最小的边
}
将该边的权值加入总权重中
将找到的点置为已选中
}//错误思路
后来我发现这样做是行不通的,因为每加入一个新的点,都需要再重新
走一遍上面的代码,也就是说我设计的算法的时间复杂度不是O(n^2)
而是O(n^3)。
算法关键的一点是如何记录已经扫描过的边,比如我从v1开始,,经历步骤②③后将v2加入了V,
如果不做处理,步骤②又会先从v1开始扫描再扫描v2,这就会增大时间复杂度。
解决:
用三个数组并且不断更新这三个数组直到找出最小生成树
selected:记录某个顶点是否已加入生成树
T:是,F:否,初始状态下所有顶点为F。
minDist:联结已选顶点集合到未选顶点的所有边中最短的那条边
初始状态下均为inf。
parent:以selected的元素为v1,minDist的元素为边,确定parent数组的值,即parent存放的是v2。
初始状态下均为-1

图片演示
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结束条件
①所有顶点都为T
②选择的边数 = 顶点数 - 1

kruskal算法:
**核心思想:**将森林合并成树
将所有边的权值按从小到大的顺序排列,若边的两顶点与选中的顶点没有构成回路,则将这两个顶点加入已选顶点中,若构成回路则跳过该边,直到所有顶点都被选中。

图片演示
在这里插入图片描述

3.设计

int prim()
{
随机选一个起点v,将该点的selected置为T
while(1)
{
for(v的每个未被收录的每个邻接点)
{
更新minDist和parent数组
}
for(v的每个未被收录的每个邻接点)
{
找出未收录顶点中dist最小的顶点u
}
置selected[u]为T
置v=u
if(全部顶点都已被收录)break;
}
}

void kruskal()
{
MST为空
while(MST中边数<|V|-1 && E不为空)
{
选取E中权重最小的边e
将e从E中删除
if(e在MST中不构成回路)将e加入MST
}
}

4.分析

prim算法:O(n^2)
kruskal算法:O(eloge)

### 最小生成树 Kruskal 算法 vs Prim 算法 #### 1. 算法思想对比 Kruskal算法是一种贪心算法,其核心在于按照边的权重从小到大依次选取不构成回路的边加入最小生成树中[^2]。而Prim算法则是从任意一个顶点开始构建最小生成树,在每次迭代过程中选择连接已有的部分剩余未访问节点之间的最短路径作为新的边加入当前的部分最小生成树内[^3]。 #### 2. 初始化方式不同 对于Kruskal算法而言,初始化时只需要将所有的边按权重升序排列即可;而对于Prim算法来说,则是从某个特定起点出发,初始状态下只有该起始结点被纳入考虑范围之内[^4]。 #### 3. 数据结构的选择差异 为了高效地执行这两种算法,所采用的数据结构也有所不同: - **Kruskal**: 使用并查集(Union-Find Set)来检测新增加的一条边是否会形成环路; - **Prim**: 则更倾向于利用优先队列(Priority Queue),比如二叉堆或斐波那契堆等高级数据结构来进行优化处理,从而快速找到下一个最优候选边。 #### 4. 时间复杂度分析 当涉及到时间效率方面: - 对于稀疏图 (edge数远小于vertex平方),由于Kruskal主要依赖于对所有edges的操作,因此它的时间性能较好; - 而针对稠密图(edge数目接近vertex数量级), Prim因为可以更好地控制局部搜索空间,所以往往表现得更为出色一些。 #### 5. Python代码实现示例 以下是两种算法简单的Python实现版本: ##### Kruskal Algorithm Implementation ```python from collections import defaultdict class Graph: def __init__(self, vertices): self.V = vertices self.graph = [] # 添加新边的方法 def addEdge(self,u,v,w): self.graph.append([u,v,w]) # 查找函数用于查找子集合 def find(self,parent,i): if parent[i] == i: return i return graph.find(parent ,parent[i]) # 合并两个子集合 def union(self,parent,rank,x,y): rootX = self.find(parent,x) rootY = self.find(parent,y) if rank[rootX] < rank[rootY]: parent[rootX]=rootY elif rank[rootX]>rank[rootY]: parent[rootY]=rootX else : parent[rootY]=rootX rank[rootX]+=1 def kruskalMST(self): result=[] e=0 self.graph=sorted(self.graph,key=lambda item:item[2]) parent=[] rank=[] for node in range(self.V): parent.append(node) rank.append(0) while(e<self.V-1 and len(self.graph)>e): u,v,w=self.graph[e] e+=1 x=self.find(parent,u) y=self.find(parent,v) if(x!=y): result.append((u,v,w)) self.union(parent,rank,x,y) minimumCost=0 print ("Edges in the constructed MST") for u,v,weight in result: minimumCost += weight print("%d -- %d == %d"%(u,v,weight)) print("Minimum Spanning Tree",minimumCost) ``` ##### Prim's Algorithm Implementation ```python import sys class Graph(): def __init__(self,vertices): self.V=vertices self.graph=[[0 for column in range(vertices)]for row in range(vertices)] def printSolution(self,dist): print("Vertex tDistance from Source") for node in range(self.V): print(node,"t",dist[node]) def minKey(self,dist,mstSet): min=sys.maxsize for v in range(self.V): if dist[v]<min and mstSet[v]==False: min=dist[v] min_index=v return min_index def primMST(self): key=[sys.maxsize]*self.V parent=[None]*self.V key[0]=0 mstSet=[False]*self.V parent[0]=-1 for cout in range(self.V): u=self.minKey(key,mstSet) mstSet[u]=True for v in range(self.V): if self.graph[u][v]>0 and mstSet[v]==False and key[v]>self.graph[u][v]: key[v]=self.graph[u][v] parent[v]=u self.printSolution(key) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值