com.salesforce.jgrapht.alg.spanning.PrimMinimumSpanningTree Maven / Gradle / Ivy
/*
* (C) Copyright 2013-2018, by Alexandru Valeanu and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* See the CONTRIBUTORS.md file distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the
* GNU Lesser General Public License v2.1 or later
* which is available at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
*
* SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
*/
package com.salesforce.jgrapht.alg.spanning;
import com.salesforce.jgrapht.*;
import com.salesforce.jgrapht.alg.interfaces.*;
import com.salesforce.jgrapht.util.*;
import java.lang.reflect.*;
import java.util.*;
/**
* An implementation of Prim's
* algorithm that finds a minimum spanning tree/forest subject to connectivity of the supplied
* weighted undirected graph. The algorithm was developed by Czech mathematician V. Jarník and later
* independently by computer scientist Robert C. Prim and rediscovered by E. Dijkstra.
*
* This implementation relies on a Fibonacci heap, and runs in $O(|E| + |V|log(|V|))$.
*
*
* @param the graph vertex type
* @param the graph edge type
*
* @author Alexandru Valeanu
* @author Alexey Kudinkin
*/
public class PrimMinimumSpanningTree
implements
SpanningTreeAlgorithm
{
private final Graph g;
/**
* Construct a new instance of the algorithm.
*
* @param graph the input graph
*/
public PrimMinimumSpanningTree(Graph graph)
{
this.g = Objects.requireNonNull(graph, "Graph cannot be null");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public SpanningTree getSpanningTree()
{
Set minimumSpanningTreeEdgeSet = new HashSet<>(g.vertexSet().size());
double spanningTreeWeight = 0d;
final int N = g.vertexSet().size();
/*
* Normalize the graph by mapping each vertex to an integer.
*/
VertexToIntegerMapping vertexToIntegerMapping = Graphs.getVertexToIntegerMapping(g);
Map vertexMap = vertexToIntegerMapping.getVertexMap();
List indexList = vertexToIntegerMapping.getIndexList();
VertexInfo[] vertices = (VertexInfo[]) Array.newInstance(VertexInfo.class, N);
FibonacciHeapNode[] fibNodes =
(FibonacciHeapNode[]) Array.newInstance(FibonacciHeapNode.class, N);
FibonacciHeap fibonacciHeap = new FibonacciHeap<>();
for (int i = 0; i < N; i++) {
vertices[i] = new VertexInfo();
vertices[i].id = i;
vertices[i].distance = Double.MAX_VALUE;
fibNodes[i] = new FibonacciHeapNode<>(vertices[i]);
fibonacciHeap.insert(fibNodes[i], vertices[i].distance);
}
while (!fibonacciHeap.isEmpty()) {
FibonacciHeapNode fibNode = fibonacciHeap.removeMin();
VertexInfo vertexInfo = fibNode.getData();
V p = indexList.get(vertexInfo.id);
vertexInfo.spanned = true;
// Add the edge from its parent to the spanning tree (if it exists)
if (vertexInfo.edgeFromParent != null) {
minimumSpanningTreeEdgeSet.add(vertexInfo.edgeFromParent);
spanningTreeWeight += g.getEdgeWeight(vertexInfo.edgeFromParent);
}
// update all (unspanned) neighbors of p
for (E e : g.edgesOf(p)) {
V q = Graphs.getOppositeVertex(g, e, p);
int id = vertexMap.get(q);
// if the vertex is not explored and we found a better edge, then update the info
if (!vertices[id].spanned) {
double cost = g.getEdgeWeight(e);
if (cost < vertices[id].distance) {
vertices[id].distance = cost;
vertices[id].edgeFromParent = e;
fibonacciHeap.decreaseKey(fibNodes[id], cost);
}
}
}
}
return new SpanningTreeImpl<>(minimumSpanningTreeEdgeSet, spanningTreeWeight);
}
private class VertexInfo
{
public int id;
public boolean spanned;
public double distance;
public E edgeFromParent;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy