1. Data structure for edges with weights
/ **
* This type of object can represent an edge in the graph
* @author lhever February 19, 2017 at 5:10:49 pm
* @version v1.0
* /
public class Edge implements Comparable <Edge>
{
private int v;
private int w;
private final double weight;
/ **
* Construction
*
* @param v
* @param w
* @param weight
* @author lhever February 19, 2017 at 5:14:30 pm
* @since v1.0
* /
public Edge (int v, int w, double weight)
{
if (v <0)
{
throw new IllegalArgumentException ("The value of vertex v must be a non-negative integer");
}
if (w <0)
{
throw new IllegalArgumentException ("The value of vertex w must be a non-negative integer");
}
if (Double.isNaN (weight))
{
throw new IllegalArgumentException ("Weight cannot be NaN");
}
this.v = v;
this.w = w;
this.weight = weight;
}
/ **
* Return weight
*
* @return
* @author lhever February 19, 2017 at 5:15:41 pm
* @since v1.0
* /
public double weight ()
{
return weight;
}
/ **
* Returns one of the vertices of the edge v
* @return
* @author lhever February 19, 2017 at 5:15:54 pm
* @since v1.0
* /
public int either ()
{
return v;
}
/ **
* Returns one vertex in addition to vertex that forms an edge
* @param vertex
* @return
* @author lhever February 19, 2017 at 5:16:16 pm
* @since v1.0
* /
public int other (int vertex)
{
if (vertex == v)
{
return w;
} else if (vertex == w)
{
return v;
} else
{
throw new IllegalArgumentException ("illegal vertex");
}
}
@Override
public int compareTo (Edge other)
{
if (this.weight () <other.weight ())
{
return -1;
} else if (this.weight ()> other.weight ())
{
return 1;
} else
{
return 0;
}
}
public String toString ()
{
return String.format ("% d-% d% .5f", v, w, weight);
}
public static void main (String [] args)
{
Edge e = new Edge (4, 5, 78.98);
System.out.println (e);
}
}
2 Weighted Graph-free data structure
import java.util.ArrayList;
import java.util.List;
public class EdgeWeightedGraph
{
private static final String NEWLINE = System.getProperty ("line.separator");
private final int V;
private int E;
private List <Edge> [] adj;
@SuppressWarnings ("unchecked")
public EdgeWeightedGraph (int V)
{
if (V <0)
{
throw new IllegalArgumentException ("Number of vertices must be non-negative");
}
this.V = V;
this.E = 0;
adj = (List <Edge> []) new ArrayList [V];
for (int v = 0; v <V; v ++)
{
adj [v] = new ArrayList <Edge> ();
}
}
public EdgeWeightedGraph (EdgeWeightedGraph G)
{
this (G.V ());
this.E = G.E ();
for (int v = 0; v <G.V (); v ++)
{
List <Edge> li = new ArrayList <Edge> ();
for (Edge e: G.adj [v])
{
li.add (e);
}
for (Edge e: li)
{
adj [v] .add (e);
}
}
}
public int V ()
{
return V;
}
public int E ()
{
return E;
}
private void validateVertex (int v)
{
if (v <0 || v> = V)
{
throw new IllegalArgumentException ("The vertex number" + v + "is not between 0 and" + (V-1) + ");
}
}
/ **
* Add edges to undirected unweighted graph
*
* @param e
* @author lhever February 19, 2017 at 5:34:00
* @since v1.0
* /
public void addEdge (Edge e)
{
int v = e. either ();
int w = e.other (v);
validateVertex (v);
validateVertex (w);
adj [v] .add (e);
adj [w] .add (e);
E ++;
}
/ **
* Returns the adjacent edge of vertex v
*
* @param v
* @return
* @author lhever February 19, 2017 at 5:35:09 pm
* @since v1.0
* /
public Iterable <Edge> adj (int v)
{
validateVertex (v);
return adj [v];
}
/ **
* Returns the degree of vertex v (number of adjacent vertices)
*
* @param v
* @return
* @author lhever February 19, 2017 at 5:36:08 pm
* @since v1.0
* /
public int degree (int v)
{
validateVertex (v);
return adj [v] .size ();
}
/ **
* Returns all edges in an undirected weighting graph
*
* @return
* @author lhever February 19, 2017 at 5:38:55 pm
* @since v1.0
* /
public Iterable <Edge> edges ()
{
List <Edge> list = new ArrayList <Edge> ();
for (int v = 0; v <V; v ++)
{
int selfLoops = 0;
for (Edge e: adj (v))
{
// In an undirected graph, the same edge will appear in the adjacency list of the two endpoints of this edge. The condition here is> to avoid duplicate search
if (e.other (v)> v)
{
list.add (e);
}
// For self-loop, such as (5, 5, 0.8), when adding an edge, it will be added twice, but it is actually only one edge, so only one
else if (e.other (v) == v)
{
if (selfLoops% 2 == 0)
{
list.add (e);
}
selfLoops ++;
}
}
}
return list;
}
public String toString ()
{
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 ();
}
public static void main (String [] args)
{
// 0 —————— 6
// / | \ |
// / | \ |
// / 1 2 |
// / |
// 5 ——————————— 4
// \ /
// \ /
// \ /
// \ /
// 3
EdgeWeightedGraph g = new EdgeWeightedGraph (7);
Edge e1 = new Edge (0, 1, 0.7);
g.addEdge (e1);
Edge e2 = new Edge (0, 2, 4.5);
g.addEdge (e2);
Edge e3 = new Edge (0, 5, 5.0);
g.addEdge (e3);
Edge e4 = new Edge (0, 6, 3.1);
g.addEdge (e4);
Edge e5 = new Edge (5, 4, 2.9);
g.addEdge (e5);
Edge e6 = new Edge (6, 4, 7.8);
g.addEdge (e6);
Edge e7 = new Edge (3, 4, 9.7);
g.addEdge (e7);
Edge e8 = new Edge (3, 5, 6.0);
g.addEdge (e8);
System.out.println (g);
EdgeWeightedGraph g1 = new EdgeWeightedGraph (g);
System.out.println (g1);
}
}
Deferred implementation of the 3 prim algorithm (when a new crosscutting edge is added to the tree to identify the failed edge)
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
/ **
* Prim algorithm for finding the minimum spanning tree of undirected unweighted graph (delayed implementation)
* @author xxx February 19, 2017 at 6:20:21 PM
* @version v1.0
* /
public class LazyPrimMST
{
private static final double FLOATING_POINT_EPSILON = 1E-12;
private double weight; // weight of minimum spanning tree
private List <Edge> mst; // all edges of the minimum spanning tree
private boolean [] marked; // if vertex v has been added to the minimum spanning tree, marked [v] = true
private PriorityQueue <Edge> pq;
public LazyPrimMST (EdgeWeightedGraph G)
{
mst = new ArrayList <Edge> ();
pq = new PriorityQueue <Edge> ();
marked = new boolean [G.V ()];
for (int v = 0; v <G.V (); v ++)
{
if (! marked [v])
{
prim (G, v);
}
}
assert check (G);
}
private void prim (EdgeWeightedGraph G, int s)
{
scan (G, s);
while (! pq.isEmpty ())
{// It is best to stop when the minimum spanning tree contains v-1 edges
// take out the edge with the smallest weight
Edge e = pq.poll ();
int v = e.either (), w = e.other (v);
assert marked [v] || marked [w];
if (marked [v] && marked [w])
{
continue;
}
mst.add (e); // edge e belongs to the edge of the minimum spanning tree
weight + = e.weight ();
// During the operation, the minimum spanning tree is gradually generated, here v is added to the current minimum tree
if (! marked [v])
{
scan (G, v);
}
// During the operation, the minimum spanning tree is gradually generated, here v is added to the current minimum tree
if (! marked [w])
{
scan (G, w);
}
}
}
/ **
* Add all adjacent edges of vertex v that meet the conditions to the priority queue,
* The condition is: another vertex of these adjacent edges has not been added to the current minimum spanning tree (not yet visited)
* @param G
* @param v
* @author xxx February 19, 2017 at 6:27:26 PM
* @since v1.0
* /
private void scan (EdgeWeightedGraph G, int v)
{
assert! marked [v];
marked [v] = true;
for (Edge e: G.adj (v))
{
if (! marked [e.other (v)])
{
pq.add (e);
}
}
}
public Iterable <Edge> edges ()
{
return mst;
}
public double weight ()
{
return weight;
}
private boolean check (EdgeWeightedGraph G)
{
// verify that the weights are consistent
double totalWeight = 0.0;
for (Edge e: edges ())
{
totalWeight + = e.weight ();
}
if (Math.abs (totalWeight-weight ())> FLOATING_POINT_EPSILON)
{
System.err.printf ("The sum of the weights of all edges of the minimum spanning tree is not consistent with the result calculated by the weight () method:% f vs.% f \ n", totalWeight, weight ());
return false;
}
// Use the connected search algorithm to determine whether it is an acyclic graph
UnionFind UnionFind = new UnionFind (G.V ());
for (Edge e: edges ())
{
int v = e.either (), w = e.other (v);
if (UnionFind.connected (v, w))
{
System.err.println ("Not a tree forest");
return false;
}
UnionFind.union (v, w);
}
// determine if it is a spanning tree
for (Edge e: G.edges ())
{
int v = e.either (), w = e.other (v);
if (! UnionFind.connected (v, w))
{
System.err.println ("Not a Spanning Tree");
return false;
}
}
// determine if it is a minimum spanning tree
for (Edge e: edges ())
{
// all edges except e in the minimum spanning tree
UnionFind = new UnionFind (G.V ());
for (Edge f: mst)
{
int x = f.either (), y = f.other (x);
if (f! = e)
{
UnionFind.union (x, y);
}
}
// check that e is min weight edge in crossing cut
for (Edge f: G.edges ())
{
int x = f.either (), y = f.other (x);
if (! UnionFind.connected (x, y))
{
if (f.weight () <e.weight ())
{
System.err.println ("Edge" + f + "Segmentation violation");
return false;
}
}
}
}
return true;
}
public static void main (String [] args)
{
// 0 —————— 6
// / | \ |
// / | \ |
// / 1 2 |
// / |
// 5 ——————————— 4
// \ /
// \ /
// \ /
// \ /
// 3
EdgeWeightedGraph g = new EdgeWeightedGraph (7);
Edge e1 = new Edge (0, 1, 0.7);
g.addEdge (e1);
Edge e2 = new Edge (0, 2, 4.5);
g.addEdge (e2);
Edge e3 = new Edge (0, 5, 5.0);
g.addEdge (e3);
Edge e4 = new Edge (0, 6, 3.1);
g.addEdge (e4);
Edge e5 = new Edge (5, 4, 2.9);
g.addEdge (e5);
Edge e6 = new Edge (6, 4, 7.8);
g.addEdge (e6);
Edge e7 = new Edge (3, 4, 9.7);
g.addEdge (e7);
Edge e8 = new Edge (3, 5, 6.0);
g.addEdge (e8);
LazyPrimMST mst = new LazyPrimMST (g);
for (Edge e: mst.edges ())
{
System.out.println (e);
}
System.out.printf ("%. 5f \ n", mst.weight ());
}
}
//////////////////// The code of the class used in the algorithm for connected search is as follows //////////////////////// ///////
import java.util.Arrays;
public class UnionFind {
private int [] parent; // parent [i] is the parent (or root) of node i
private byte [] rank; // rank [i] is the rank of the subtree with i as the root node
private int count; // number of connected components
/ **
* Initialize the data structure of a connectivity-finding algorithm, N represents the nodes (or vertices, or electric shock) in the data structure, and just initialized
* Data structure, each node is located in its own connected component, that is, N connected components
* @param N
* @author xxx February 28, 2017 at 12:14:48 am
* @since v1.0
* /
public UnionFind (int N)
{
if (N <0)
{
throw new IllegalArgumentException ();
}
count = N;
parent = new int [N];
rank = new byte [N];
for (int i = 0; i <N; i ++)
{
parent [i] = i;
rank [i] = 0;
}
}
/ **
* Returns the id (or identifier) of the connected component containing node p
* @param p
* @return
* @author xxx February 28, 2017 at 12:26:19 am
* @since v1.0
* /
public int find (int p)
{
validate (p);
while (p! = parent [p])
{
parent [p] = parent [parent [p]]; // path compression
p = parent [p];
}
return p;
}
/ **
* Returns the total number of connected components
* @return
* @author xxx February 28, 2017 at 12:21:16 am
* @since v1.0
* /
public int count ()
{
return count;
}
/ **
* True if node p and node q are in the same connected component
* @param p
* @param q
* @return
* @author xxx February 28, 2017 at 12:20:35 am
* @since v1.0
* /
public boolean connected (int p, int q)
{
return find (p) == find (q);
}
/ **
* Combine connected components containing node p with connected components containing node q
* @param p
* @param q
* @author xxx February 28, 2017 at 12:19:24 am
* @since v1.0
* /
public void union (int p, int q)
{
int rootP = find (p);
int rootQ = find (q);
if (rootP == rootQ)
{
return;
}
// make root of smaller rank point to root of larger rank
if (rank [rootP] <rank [rootQ])
{
parent [rootP] = rootQ;
} else if (rank [rootP]> rank [rootQ])
{
parent [rootQ] = rootP;
}