[Java]图论进阶--最小生成树算法


 专栏简介 :java语法及数据结构

题目来源:leetcode,牛客,剑指offer.

创作目标:记录学习MySql学习历程

希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长.

学历代表过去,能力代表现在,学习能力代表未来! 


目录

1. 最小生成树

1.1 Kruskal(克鲁斯卡尔) 算法

1.2 Prime(普里姆) 算法


1. 最小生成树

连通图中的每一棵生成树 , 都是原图的极大无环子图 , 即: 从中删去任何一条边 , 生成树就不再连通;反之 , 在其中引入任何一条新边 , 都会形成一条回路.

若连通图由n个顶点组成 , 则其生成树必含n个顶点和n-1条边 , 因此构造最小生成树有三个准则:

  • 1.只能使用图中的边来构造最小生成树
  • 2.只能使用恰好n-1条边来连接图中的n个顶点
  • 3.选用的n-1条边不能构成回路 

常见求解最小生成树的算法有: Kruskal算法和Prime算法.两种算法都采用逐步求解的贪心策略.

贪心算法: 通过局部最优解来推出全局最优解.


1.1 Kruskal(克鲁斯卡尔) 算法

给定一个有n个顶点的连通网络N={V,E}

首先构造一个由这n个顶点组成 , 不含任何边的图G={V,NULL}.

其次不断从E中取出权值最小的一条边(若有多条任选其一) , 若该边的两个顶点来自不同的连通分量 , 则将此边加入到G中.

如此反复 , 直到G中边数达到顶点数-1为止.

核心: 每次迭代时 , 选出权值最小且两端点不在同一连通分量上的边 , 加入生成树.

步骤分析:

  • 1.由于该算法的思想是全局贪心 , 因此将所有图中所有边全部放入优先级队列中.
  • 2.构造一个最小生成树 ,
最小生成树是指在一个加权无向图中,找到一棵包含所有顶点的树,并且它的边权重之和尽可能小。在Java中,最常用的算法实现是Prim算法和Kruskal算法。 **Prim算法** (也称为贪心策略) 的Java实现可以这样写: ```java import java.util.*; class Prim { private int V; // 图的顶点数 private List<Edge>[] adj; // 邻接表表示的邻接矩阵 private boolean[] marked; // 标记已访问的节点 private int minDistance[]; // 存储每个顶点到已构成树中的最短距离 // 构建Prim算法所需的辅助函数 private class Edge implements Comparable<Edge> { int src, dest, weight; Edge(int src, int dest, int weight) { this.src = src; this.dest = dest; this.weight = weight; } @Override public int compareTo(Edge other) { return Integer.compare(this.weight, other.weight); } } // 主函数,输入邻接列表并返回最小生成树的总重量 int primMST() { marked = new boolean[V]; minDistance = new int[V]; Arrays.fill(minDistance, Integer.MAX_VALUE); minDistance[0] = 0; int totalWeight = 0; for (int count = 0; count < V - 1; count++) { int u = findMinDistance(); marked[u] = true; for (Edge edge : adj[u]) { int v = edge.dest; if (!marked[v] && edge.weight < minDistance[v]) { minDistance[v] = edge.weight; } } totalWeight += minDistance[u]; } return totalWeight; } // 找到未标记节点中距离当前生成树最近的一个 int findMinDistance() { int min = Integer.MAX_VALUE, min_index = -1; for (int i = 0; i < V; i++) { if (!marked[i] && min > minDistance[i]) min = minDistance[i], min_index = i; } return min_index; } // 添加边到邻接表 void addEdge(int src, int dest, int weight) { adj[src].add(new Edge(src, dest, weight)); } } // 示例: public static void main(String args[]) { Prim graph = new Prim(); int V = 5; // 图的顶点数 graph.addEdge(0, 1, 10); // 边0-1,权重10 graph.addEdge(0, 4, 6); // 边0-4,权重6 graph.addEdge(1, 2, 8); // 边1-2,权重8 graph.addEdge(1, 3, 7); // 边1-3,权重7 graph.addEdge(2, 3, 9); // 边2-3,权重9 graph.addEdge(3, 4, 5); // 边3-4,权重5 System.out.println("Minimum spanning tree using Prim's algorithm has weight " + graph.primMST()); } ``` **Kruskal算法** 则是另一种选择,它通过从小到大顺序考虑所有边,并只加入不会形成环的边。以下是Kruskal算法的简化版: ```java class Kruskal { // ... (省略部分实现细节) } public static void main(String[] args) { Kruskal kruskal = new Kruskal(); // 添加边到森林中... int mstWeight = kruskal.buildMST(); // 建立最小生成树 System.out.println("Minimum spanning tree using Kruskal's algorithm has weight " + mstWeight); } ```
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Node_Hao

您的支持是我创作的不懈动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值