最小生成树-克鲁斯卡尔算法(kruskal's algorithm)实现
算法描述
克鲁斯卡尔算法是一种贪心算法,因为它每一步都挑选当前最轻的边而并不知道全局路径的情况.
算法最关键的一个步骤是要判断要加入mst的顶点是否会形成回路,我们可以利用并查集的技术来做。
并查集的具体实现可参考:快速并查集
下面是对算法的一个简单描述:
这是一个非常简单易懂的算法,它面向边而不是顶点,所以在算法开始的时候,它要先找出所有的crossing edges,而为了高效的找到最轻边,用一个优先队列来维护这些crossing edges.
/**
* 找出所有crossing edges并加入优先队列
*/
private void findAllCrossingEdges(){
for(Vertex v:this.vertices) {
for(Edge edge:v.Adj) {
WeightedEdge we = (WeightedEdge)edge;
this.crossingEdges.add(we);
}
}
}
private PriorityQueue<WeightedEdge> crossingEdges = new PriorityQueue<WeightedEdge>();
算法实现
下面是克鲁斯卡尔算法的一个实现:
/**
* 克鲁斯卡尔算法求MST
*
* 克鲁斯尔卡算法也是一种贪心算法(greedy algorithm)
* 1.总是挑选最轻的边,如果这条边的两个端点没有形成回路,就将这条边加入MST
* 2.在剩下的边中,重复1.
*
*/
public void kruskalMST() {
resetMemo();
//找出所有crossing edges
findAllCrossingEdges();
//初始化并查集
FastUnionFind uf = new FastUnionFind(vertexCount());
//算法用贪心策略,每一步都挑选最轻的边来加入mst
//需要注意的是,在加入mst之前要考察边的两端顶点是否形成环路
while (!this.crossingEdges.isEmpty()) {
//最轻边
WeightedEdge edge = crossingEdges.poll();
//如果点src和点to没有形成环
if(!uf.isConnected(edge.src,edge.to)){
//将src和to连通
uf.union(edge.src,edge.to);
//将最轻边加入mst
mst.offer(edge);
//更新mst的权重
mstWeight += edge.weight;
}
}
}
时间复杂度
算法需要对所有边E 进行访问,这步操作耗时O(E )
将边入队和出队的操作耗时O(logE).
由于假设图是连通的,并查判断回路操作耗时O(logE)
所以整体耗时O(ElogE ).
由于 |E| < V*V,所以logE = 2logV,则可将算法复杂度写为O(ElogV).
【版权所有@foreach_break】
【博客地址 http://www.cnblogs.com/foreach-break】
可以转载,但必须注明出处并保持博客超链接
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?