最小生成树之prim算法概念与实现
来源:互联网 发布:管家婆数据导入失败 编辑:程序博客网 时间:2024/06/04 19:38
基本概念
prim算法是以顶点为视角的,每一步都会为生长中的树添加一条边。从初始顶点出发,然后找到顶点周围最小的边,然后移动到最小边的另一个端点,继续找到顶点周围最小的边,直到得到最小生成树。所以prim算法的轨迹是一颗从初始顶点不断蔓延的树。
prim算法懒惰实现
prim算法的懒惰实现很简单,将需要考察的顶点的边放进一个优先队列中,并考察边的顶点是否存在于最小生成树中或者是否形成一个环。如果都没有,就将边放进MST。
/** * 懒惰实现普里姆斯算法 * @author yuli * */public class LazyPrimMst { private boolean[] marked;//标记最小生成树的顶点已经被访问过了 private Queue<Edge> mst;//最小生成树容器 private PriorityQueue<Edge> pq;//横切边优先队列 public LazyPrimMst(EdgeWeightedGraph graph){ pq = new PriorityQueue<>(); mst = new LinkedList<Edge>(); marked = new boolean[graph.getV()]; //将最开始的节点放进mst,并把最开始的节点的邻接点放进优先队列 visit(graph,0); while(!pq.isEmpty()){ //从优先队列中得到权值最小的边 Edge e = pq.poll(); //得到两个顶点 int v = e.getV();int w = e.getW(); //跳过已经加入mst的边 if(marked[v] && marked[w]) continue; //将权重最小的边加入mst中 mst.add(e); //标记已经被加入到mst中的顶点,并把他们的邻接点加入到优先队列中 if(!marked[v]) visit(graph, v); if(!marked[w]) visit(graph, w); } } /** * 将顶点放进mst中 * @param graph * @param v */ private void visit(EdgeWeightedGraph graph,int v){ //标记顶点已经在mst中了 marked[v] = true; Iterable<Edge> adj = graph.adj(v); //将顶点没被访问过(加入mst)的邻接点放进优先队列中 for (Edge edge : adj) { if(!marked[edge.other(v)]){ pq.add(edge); } } } /** * 获取最小生成树 * @return */ public Iterable<Edge> edges(){ return mst; } /** * 获取最小生成树的权重 * @return */ public double weight(){ double weight = 0; Iterable<Edge> edges = edges(); for (Edge edge : edges) { weight += edge.getWeight(); } return weight; }}
prim算法的即时实现
prim的懒惰算法简单方便,然是在把所有边都放进优先队列的做法不够优雅,会消耗很多的内存和性能。所以出现了prim算法的即时实现。
即时的prim算法会逐个考察通向顶点的最优边(权重最小)。因为贪心算法的缘故,通向顶点最小的权值边一定会组成一个最小生成树。
用一个索引优先队列维护通向最小生成树的最近的顶点
将需要考察的顶点放进索引优先队列中,考察通向这个顶点的最近的边,如果有更新权值。考察完后将队列中离树最近的顶点出队并加入到树中。
/** * 普里姆算法即时实现 * @author yuli * */public class PrimMst { private Edge[] edgeTo;//距离树最近的边 private double[] distTo;//最近边的权重 private boolean[] marked;//是否在树中 private IndexMinPQ<Double> pq;//最小索引优先队列,用来维护到树的最短距离,最小权重 public PrimMst(EdgeWeightedGraph graph) { edgeTo = new Edge[graph.getV()]; distTo = new double[graph.getV()]; marked = new boolean[graph.getV()]; pq = new IndexMinPQ<>(graph.getV());//初始化索引优先队列 for(int i = 0;i<graph.getV();i++){ distTo[i] = Double.POSITIVE_INFINITY;//初始化权重,最大化 } //把顶点0设置为最小,并考察 distTo[0] = 0.0d; pq.insert(0, 0.0d); while(!pq.isEmpty()){ //出队优先队列中最小的顶点,也就是离树最近的那个顶点。 visit(graph,pq.delMin()); } } private void visit(EdgeWeightedGraph graph, int v) { //将顶点设置为已经考察过了,加入树中 marked[v] = true; //获取已经加入树中的顶点的邻接点 for(Edge e:graph.adj(v)){ int w = e.other(v);//获取通往顶点(同往树)的另一个端点 //如果该端点已经被考察过了,就说明该端点已经存在于树中了,所以跳过 if(marked[w]){ continue; } //如果当前的边权重比离端点最近的一条边的权重轻,就替换掉 if(e.getWeight() < distTo[w]){ //记录到端点的最短边为多少 distTo[w] = e.getWeight(); //记录到端点最短路径 edgeTo[w] = e; //如果队列中中包含该索引(顶点),就添加顶点到队列中,这个队列是记录离树最近的端点 if(pq.contains(w)){ //修改该端点离树的距离 pq.change(w, distTo[w]); }else{ //添加队列中到树的最短距离 pq.insert(w, distTo[w]); } } } } /** * 获取最小生成树 * @return */ public Iterable<Edge> edges(){ List<Edge> edges = new ArrayList<>(); for (Edge edge : edgeTo) { if(edge != null){ edges.add(edge); } } return edges; } /** * 获取最小生成树的权重 * @return */ public double weight(){ double weight = 0; Iterable<Edge> edges = edges(); for (Edge edge : edges) { weight += edge.getWeight(); } return weight; }}
阅读全文
0 0
- 最小生成树之prim算法概念与实现
- 最小生成树之Prim算法实现
- 最小生成树之kruskal算法概念与实现
- 【图论】最小生成树之prim算法与kruskal算法
- 最小生成树之prim算法与kruskal算法
- 《算法4》最小生成树之Prim与Kruskal算法
- C++实现Prim与Kruskal最小生成树算法
- 求图的最小生成树之--Prim算法实现
- 最小生成树之Prim算法的实现
- 最小生成树之prim的算法实现
- 数据结构(C实现)------- 最小生成树之Prim算法
- 最小生成树之Prim算法C++实现
- 数据结构之图---最小生成树Prim算法---C++实现
- 最小生成树算法之Prim算法
- 最小生成树算法之Prim算法
- 最小生成树算法之prim算法
- 最小生成树Prim算法实现
- 最小生成树的prim算法实现
- 103. Binary Tree Zigzag Level Order Traversal
- LeetCode
- Kylin在CDH中的安装
- 编写一个程序计算后缀表达式的值
- 表情识别训练过程
- 最小生成树之prim算法概念与实现
- 整数划分 51Nod
- 堆和堆排序
- 内存对齐
- python单元测试框架
- poj 1313 Booklet Printing 模拟水题
- unity点乘和叉乘的使用
- CCF201703-1 分蛋糕
- Mac上强大的清理工具CleanMyMac 激活码 免费下载