package com.jwetherell.algorithms.data_structures;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* Graph. Could be directed or undirected depending on the TYPE enum. A graph is
* an abstract representation of a set of objects where some pairs of the
* objects are connected by links.
*
* http://en.wikipedia.org/wiki/Graph_(mathematics)
*
* @author Justin Wetherell <phishman3579@gmail.com>
*/
@SuppressWarnings("unchecked")
public class Graph<T extends Comparable<T>> {
private List<Vertex<T>> allVertices = new ArrayList<Vertex<T>>();
private List<Edge<T>> allEdges = new ArrayList<Edge<T>>();
public enum TYPE {
DIRECTED, UNDIRECTED
}
/** Defaulted to undirected */
private TYPE type = TYPE.UNDIRECTED;
public Graph() { }
public Graph(TYPE type) {
this.type = type;
}
/** Deep copies **/
public Graph(Graph<T> g) {
type = g.getType();
// Copy the vertices which also copies the edges
for (Vertex<T> v : g.getVertices())
this.allVertices.add(new Vertex<T>(v));
for (Vertex<T> v : this.getVertices()) {
for (Edge<T> e : v.getEdges()) {
this.allEdges.add(e);
}
}
}
/**
* Creates a Graph from the vertices and edges. This defaults to an undirected Graph
*
* NOTE: Duplicate vertices and edges ARE allowed.
* NOTE: Copies the vertex and edge objects but does NOT store the Collection parameters itself.
*
* @param vertices Collection of vertices
* @param edges Collection of edges
*/
public Graph(Collection<Vertex<T>> vertices, Collection<Edge<T>> edges) {
this(TYPE.UNDIRECTED, vertices, edges);
}
/**
* Creates a Graph from the vertices and edges.
*
* NOTE: Duplicate vertices and edges ARE allowed.
* NOTE: Copies the vertex and edge objects but does NOT store the Collection parameters itself.
*
* @param vertices Collection of vertices
* @param edges Collection of edges
*/
public Graph(TYPE type, Collection<Vertex<T>> vertices, Collection<Edge<T>> edges) {
this(type);
this.allVertices.addAll(vertices);
this.allEdges.addAll(edges);
for (Edge<T> e : edges) {
final Vertex<T> from = e.from;
final Vertex<T> to = e.to;
if (!this.allVertices.contains(from) || !this.allVertices.contains(to))
continue;
from.addEdge(e);
if (this.type == TYPE.UNDIRECTED) {
Edge<T> reciprical = new Edge<T>(e.cost, to, from);
to.addEdge(reciprical);
this.allEdges.add(reciprical);
}
}
}
public TYPE getType() {
return type;
}
public List<Vertex<T>> getVertices() {
return allVertices;
}
public List<Edge<T>> getEdges() {
return allEdges;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
int code = this.type.hashCode() + this.allVertices.size() + this.allEdges.size();
for (Vertex<T> v : allVertices)
code *= v.hashCode();
for (Edge<T> e : allEdges)
code *= e.hashCode();
return 31 * code;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object g1) {
if (!(g1 instanceof Graph))
return false;
final Graph<T> g = (Graph<T>) g1;
final boolean typeEquals = this.type == g.type;
if (!typeEquals)
return false;
final boolean verticesSizeEquals = this.allVertices.size() == g.allVertices.size();
if (!verticesSizeEquals)
return false;
final boolean edgesSizeEquals = this.allEdges.size() == g.allEdges.size();
if (!edgesSizeEquals)
return false;
// Vertices can contain duplicates and appear in different order but both arrays should contain the same elements
final Object[] ov1 = this.allVertices.toArray();
Arrays.sort(ov1);
final Object[] ov2 = g.allVertices.toArray();
Arrays.sort(ov2);
for (int i=0; i<ov1.length; i++) {
final Vertex<T> v1 = (Vertex<T>) ov1[i];
final Vertex<T> v2 = (Vertex<T>) ov2[i];
if (!v1.equals(v2))
return false;
}
// Edges can contain duplicates and appear in different order but both arrays should contain the same elements
final Object[] oe1 = this.allEdges.toArray();
Arrays.sort(oe1);
final Object[] oe2 = g.allEdges.toArray();
Arrays.sort(oe2);
for (int i=0; i<oe1.length; i++) {
final Edge<T> e1 = (Edge<T>) oe1[i];
final Edge<T> e2 = (Edge<T>) oe2[i];
if (!e1.equals(e2))
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
for (Vertex<T> v : allVertices)
builder.append(v.toString());
return builder.toString();
}
public static class Vertex<T extends Comparable<T>> implements Comparable<Vertex<T>> {
private T value = null;
private int weight = 0;
private List<Edge<T>> edges = new ArrayList<Edge<T>>();
public Vertex(T value) {
this.value = value;
}
public Vertex(T value, int weight) {
this(value);
this.weight = weight;
}
/** Deep copies the edges along with the value and weight **/
public Vertex(Vertex<T> vertex) {
this(vertex.value, vertex.weight);
this.edges.addAll(vertex.edges);
}
public T getValue() {
return value;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public void addEdge(Edge<T> e) {
edges.add(e);
}
public List<Edge<T>> getEdges() {
return edges;
}
public Edge<T> getEdge(Vertex<T> v) {
for (Edge<T> e : edges) {
if (e.to.equals(v))
return e;
}
return null;
}
public boolean pathTo(Vertex<T> v) {
for (Edge<T> e : edges) {
if (e.to.equals(v))
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int code = this.value.hashCode() + this.weight + this.edges.size();
return 31 * code;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object v1) {
if (!(v1 instanceof Vertex))
return false;
final Vertex<T> v = (Vertex<T>) v1;
final boolean weightEquals = this.weight == v.weight;
if (!weightEquals)
return false;
final boolean edgesSizeEquals = this.edges.size() == v.edges.size();
if (!edgesSizeEquals)
return false;
final boolean valuesEquals = this.value.equals(v.value);
if (!valuesEquals)
return false;
final Iterator<Edge<T>> iter1 = this.edges.iterator();
final Iterator<Edge<T>> iter2 = v.edges.iterator();
while (iter1.hasNext() && iter2.hasNext()) {
// Only checking the cost
final Edge<T> e1 = iter1.next();
final Edge<T> e2 = iter2.next();
if (e1.cost != e2.cost)
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(Vertex<T> v) {
final int valueComp = this.value.compareTo(v.value);
if (valueComp != 0)
return valueComp;
if (this.weight < v.weight)
return -1;
if (this.weight > v.weight)
return 1;
if (this.edges.size() < v.edges.size())
return -1;
if (this.edges.size() > v.edges.size())
return 1;
final Iterator<Edge<T>> iter1 = this.edges.iterator();
final Iterator<Edge<T>> iter2 = v.edges.iterator();
while (iter1.hasNext() && iter2.hasNext()) {
// Only checking the cost
final Edge<T> e1 = iter1.next();
final Edge<T> e2 = iter2.next();
if (e1.cost < e2.cost)
return -1;
if (e1.cost > e2.cost)
return 1;
}
return 0;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Value=").append(value).append(" weight=").append(weight).append("\n");
for (Edge<T> e : edges)
builder.append("\t").append(e.toString());
return builder.toString();
}
}
public static class Edge<T extends Comparable<T>> implements Comparable<Edge<T>> {
private Vertex<T> from = null;
private Vertex<T> to = null;
private int cost = 0;
public Edge(int cost, Vertex<T> from, Vertex<T> to) {
if (from == null || to == null)
throw (new NullPointerException("Both 'to' and 'from' vertices need to be non-NULL."));
this.cost = cost;
this.from = from;
this.to = to;
}
public Edge(Edge<T> e) {
this(e.cost, e.from, e.to);
}
public int getCost() {
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
public Vertex<T> getFromVertex() {
return from;
}
public Vertex<T> getToVertex() {
return to;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int cost = (this.cost * (this.getFromVertex().hashCode() * this.getToVertex().hashCode()));
return 31 * cost;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object e1) {
if (!(e1 instanceof Edge))
return false;
final Edge<T> e = (Edge<T>) e1;
final boolean costs = this.cost == e.cost;
if (!costs)
return false;
final boolean from = this.from.equals(e.from);
if (!from)
return false;
final boolean to = this.to.equals(e.to);
if (!to)
return false;
return true;
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(Edge<T> e) {
if (this.cost < e.cost)
return -1;
if (this.cost > e.cost)
return 1;
final int from = this.from.compareTo(e.from);
if (from != 0)
return from;
final int to = this.to.compareTo(e.to);
if (to != 0)
return to;
return 0;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[ ").append(from.value).append("(").append(from.weight).append(") ").append("]").append(" -> ")
.append("[ ").append(to.value).append("(").append(to.weight).append(") ").append("]").append(" = ").append(cost).append("\n");
return builder.toString();
}
}
public static class CostVertexPair<T extends Comparable<T>> implements Comparable<CostVertexPair<T>> {
private int cost = Integer.MAX_VALUE;
private Vertex<T> vertex = null;
public CostVertexPair(int cost, Vertex<T> vertex) {
if (vertex == null)
throw (new NullPointerException("vertex cannot be NULL."));
this.cost = cost;
this.vertex = vertex;
}
public int getCost() {
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
public Vertex<T> getVertex() {
return vertex;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return 31 * (this.cost * ((this.vertex!=null)?this.vertex.hashCode():1));
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object e1) {
if (!(e1 instanceof CostVertexPair))
return false;
final CostVertexPair<?> pair = (CostVertexPair<?>)e1;
if (this.cost != pair.cost)
return false;
if (!this.vertex.equals(pair.vertex))
return false;
return true;
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(CostVertexPair<T> p) {
if (p == null)
throw new NullPointerException("CostVertexPair 'p' must be non-NULL.");
if (this.cost < p.cost)
return -1;
if (this.cost > p.cost)
return 1;
return 0;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(vertex.getValue()).append(" (").append(vertex.weight).append(") ").append(" cost=").append(cost).append("\n");
return builder.toString();
}
}
public static class CostPathPair<T extends Comparable<T>> {
private int cost = 0;
private List<Edge<T>> path = null;
public CostPathPair(int cost, List<Edge<T>> path) {
if (path == null)
throw (new NullPointerException("path cannot be NULL."));
this.cost = cost;
this.path = path;
}
public int getCost() {
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
public List<Edge<T>> getPath() {
return path;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
int hash = this.cost;
for (Edge<T> e : path)
hash *= e.cost;
return 31 * hash;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CostPathPair))
return false;
final CostPathPair<?> pair = (CostPathPair<?>) obj;
if (this.cost != pair.cost)
return false;
final Iterator<?> iter1 = this.getPath().iterator();
final Iterator<?> iter2 = pair.getPath().iterator();
while (iter1.hasNext() && iter2.hasNext()) {
Edge<T> e1 = (Edge<T>) iter1.next();
Edge<T> e2 = (Edge<T>) iter2.next();
if (!e1.equals(e2))
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Cost = ").append(cost).append("\n");
for (Edge<T> e : path)
builder.append("\t").append(e);
return builder.toString();
}
}
}