programming-examples/java/Graph_Problems_Algorithms/Java Program to Use Boruvka’s Algorithm to Find the Minimum Spanning Tree.java

494 lines
14 KiB
Java
Raw Normal View History

2019-11-15 12:59:38 +01:00
/*This is a java program to find the minimum spanning tree of a graph. Given a connected, undirected graph, a spanning tree of that graph is a subgraph that is a tree and connects all the vertices together. A single graph can have many different spanning trees. We can also assign a weight to each edge, which is a number representing how unfavorable it is, and use this to assign a weight to a spanning tree by computing the sum of the weights of the edges in that spanning tree. A minimum spanning tree (MST) or minimum weight spanning tree is then a spanning tree with weight less than or equal to the weight of every other spanning tree. More generally, any undirected graph (not necessarily connected) has a minimum spanning forest, which is a union of minimum spanning trees for its connected components.*/
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Scanner;
public class BoruvkasMST
{
private Bag<Edge> mst = new Bag<Edge>(); // Edge in MST
private double weight; // weight of MST
public BoruvkasMST(EdgeWeightedGraph G)
{
UF uf = new UF(G.V());
// repeat at most log V times or until we have V-1 Edge
for (int t = 1; t < G.V() && mst.size() < G.V() - 1; t = t + t)
{
// foreach tree in forest, find closest edge
// if edge weights are equal, ties are broken in favor of first edge
// in G.Edge()
Edge[] closest = new Edge[G.V()];
for (Edge e : G.Edge())
{
int v = e.either(), w = e.other(v);
int i = uf.find(v), j = uf.find(w);
if (i == j)
continue; // same tree
if (closest[i] == null || less(e, closest[i]))
closest[i] = e;
if (closest[j] == null || less(e, closest[j]))
closest[j] = e;
}
// add newly discovered Edge to MST
for (int i = 0; i < G.V(); i++)
{
Edge e = closest[i];
if (e != null)
{
int v = e.either(), w = e.other(v);
// don't add the same edge twice
if (!uf.connected(v, w))
{
mst.add(e);
weight += e.weight();
uf.union(v, w);
}
}
}
}
// check optimality conditions
assert check(G);
}
public Iterable<Edge> Edge()
{
return mst;
}
public double weight()
{
return weight;
}
// is the weight of edge e strictly less than that of edge f?
private static boolean less(Edge e, Edge f)
{
return e.weight() < f.weight();
}
// check optimality conditions (takes time proportional to E V lg* V)
private boolean check(EdgeWeightedGraph G)
{
// check weight
double totalWeight = 0.0;
for (Edge e : Edge())
{
totalWeight += e.weight();
}
double EPSILON = 1E-12;
if (Math.abs(totalWeight - weight()) > EPSILON)
{
System.err.printf(
"Weight of Edge does not equal weight(): %f vs. %f\n",
totalWeight, weight());
return false;
}
// check that it is acyclic
UF uf = new UF(G.V());
for (Edge e : Edge())
{
int v = e.either(), w = e.other(v);
if (uf.connected(v, w))
{
System.err.println("Not a forest");
return false;
}
uf.union(v, w);
}
// check that it is a spanning forest
for (Edge e : G.Edge())
{
int v = e.either(), w = e.other(v);
if (!uf.connected(v, w))
{
System.err.println("Not a spanning forest");
return false;
}
}
// check that it is a minimal spanning forest (cut optimality
// conditions)
for (Edge e : Edge())
{
// all Edge in MST except e
uf = new UF(G.V());
for (Edge f : mst)
{
int x = f.either(), y = f.other(x);
if (f != e)
uf.union(x, y);
}
// check that e is min weight edge in crossing cut
for (Edge f : G.Edge())
{
int x = f.either(), y = f.other(x);
if (!uf.connected(x, y))
{
if (f.weight() < e.weight())
{
System.err.println("Edge " + f
+ " violates cut optimality conditions");
return false;
}
}
}
}
return true;
}
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
System.out.println("Enter the number of verties: ");
EdgeWeightedGraph G = new EdgeWeightedGraph(sc.nextInt());
BoruvkasMST mst = new BoruvkasMST(G);
System.out.println("MST: ");
for (Edge e : mst.Edge())
{
System.out.println(e);
}
System.out.printf("Total weight of MST: %.5f\n", mst.weight());
sc.close();
}
}
class BagOfItems<Item> implements Iterable<Item>
{
private int N; // number of elements in bag
private Node<Item> first; // beginning of bag
// helper linked list class
private static class Node<Item>
{
private Item item;
private Node<Item> next;
}
public BagOfItems()
{
first = null;
N = 0;
}
public boolean isEmpty()
{
return first == null;
}
public int size()
{
return N;
}
public void add(Item item)
{
Node<Item> oldfirst = first;
first = new Node<Item>();
first.item = item;
first.next = oldfirst;
N++;
}
public Iterator<Item> iterator()
{
return new ListIterator<Item>(first);
}
// an iterator, doesn't implement remove() since it's optional
@SuppressWarnings("hiding")
private class ListIterator<Item> implements Iterator<Item>
{
private Node<Item> current;
public ListIterator(Node<Item> first)
{
current = first;
}
public boolean hasNext()
{
return current != null;
}
public void remove()
{
throw new UnsupportedOperationException();
}
public Item next()
{
if (!hasNext())
throw new NoSuchElementException();
Item item = current.item;
current = current.next;
return item;
}
}
}
class EdgeWeightedGraph
{
private final int V;
private final int E;
private Bag<Edge>[] adj;
@SuppressWarnings("unchecked")
public EdgeWeightedGraph(int V)
{
Scanner sc = new Scanner(System.in);
if (V < 0)
{
sc.close();
throw new IllegalArgumentException(
"Number of vertices must be nonnegative");
}
this.V = V;
adj = (Bag<Edge>[]) new Bag[V];
for (int v = 0; v < V; v++)
{
adj[v] = new Bag<Edge>();
}
System.out.println("Enter the number of Edge: ");
E = sc.nextInt();
if (E < 0)
{
sc.close();
throw new IllegalArgumentException(
"Number of Edge must be nonnegative");
}
System.out.println("Enter the Edge: <from> <to>");
for (int i = 0; i < E; i++)
{
int v = sc.nextInt();
int w = sc.nextInt();
double weight = Math.round(100 * Math.random()) / 100.0;
System.out.println(weight);
Edge e = new Edge(v, w, weight);
addEdge(e);
}
sc.close();
}
public int V()
{
return V;
}
public int E()
{
return E;
}
public void addEdge(Edge e)
{
int v = e.either();
int w = e.other(v);
if (v < 0 || v >= V)
throw new IndexOutOfBoundsException("vertex " + v
+ " is not between 0 and " + (V - 1));
if (w < 0 || w >= V)
throw new IndexOutOfBoundsException("vertex " + w
+ " is not between 0 and " + (V - 1));
adj[v].add(e);
adj[w].add(e);
}
public Iterable<Edge> adj(int v)
{
if (v < 0 || v >= V)
throw new IndexOutOfBoundsException("vertex " + v
+ " is not between 0 and " + (V - 1));
return adj[v];
}
public Iterable<Edge> Edge()
{
Bag<Edge> list = new Bag<Edge>();
for (int v = 0; v < V; v++)
{
int selfLoops = 0;
for (Edge e : adj(v))
{
if (e.other(v) > v)
{
list.add(e);
}
// only add one copy of each self loop (self loops will be
// consecutive)
else if (e.other(v) == v)
{
if (selfLoops % 2 == 0)
list.add(e);
selfLoops++;
}
}
}
return list;
}
public String toString()
{
String NEWLINE = System.getProperty("line.separator");
StringBuilder s = new StringBuilder();
s.append(V + " " + E + NEWLINE);
for (int v = 0; v < V; v++)
{
s.append(v + ": ");
for (Edge e : adj[v])
{
s.append(e + " ");
}
s.append(NEWLINE);
}
return s.toString();
}
}
class Edge implements Comparable<Edge>
{
private final int v;
private final int w;
private final double weight;
public Edge(int v, int w, double weight)
{
if (v < 0)
throw new IndexOutOfBoundsException(
"Vertex name must be a nonnegative integer");
if (w < 0)
throw new IndexOutOfBoundsException(
"Vertex name must be a nonnegative integer");
if (Double.isNaN(weight))
throw new IllegalArgumentException("Weight is NaN");
this.v = v;
this.w = w;
this.weight = weight;
}
public double weight()
{
return weight;
}
public int either()
{
return v;
}
public int other(int vertex)
{
if (vertex == v)
return w;
else if (vertex == w)
return v;
else
throw new IllegalArgumentException("Illegal endpoint");
}
public int compareTo(Edge that)
{
if (this.weight() < that.weight())
return -1;
else if (this.weight() > that.weight())
return +1;
else
return 0;
}
public String toString()
{
return String.format("%d-%d %.5f", v, w, weight);
}
}
class UF
{
private int[] id; // id[i] = parent of i
private byte[] rank; // rank[i] = rank of subtree rooted at i (cannot be
// more than 31)
private int count; // number of components
public UF(int N)
{
if (N < 0)
throw new IllegalArgumentException();
count = N;
id = new int[N];
rank = new byte[N];
for (int i = 0; i < N; i++)
{
id[i] = i;
rank[i] = 0;
}
}
public int find(int p)
{
if (p < 0 || p >= id.length)
throw new IndexOutOfBoundsException();
while (p != id[p])
{
id[p] = id[id[p]]; // path compression by halving
p = id[p];
}
return p;
}
public int count()
{
return count;
}
public boolean connected(int p, int q)
{
return find(p) == find(q);
}
public void union(int p, int q)
{
int i = find(p);
int j = find(q);
if (i == j)
return;
// make root of smaller rank point to root of larger rank
if (rank[i] < rank[j])
id[i] = j;
else if (rank[i] > rank[j])
id[j] = i;
else
{
id[j] = i;
rank[i]++;
}
count--;
}
}
/*
Enter the number of verties:
6
Enter the number of Edge:
7
Enter the Edge: <from> <to>
0 1
0.09
1 2
0.48
1 3
0.52
3 4
0.43
4 5
0.98
5 3
0.07
5 2
0.1
MST:
1-2 0.48000
3-4 0.43000
5-3 0.07000
5-2 0.10000
0-1 0.09000
Total weight of MST: 1.17000