/******************************************************************************
* Compilation: javac Graph.java
* Execution: java Graph < input.txt
* Dependencies: ST.java SET.java In.java StdOut.java
* Data files: https://introcs.cs.princeton.edu/java/45graph/tinyGraph.txt
*
* Undirected graph data type implemented using a symbol table
* whose keys are vertices (String) and whose values are sets
* of neighbors (SET of Strings).
*
* Remarks
* -------
* - Parallel edges are not allowed
* - Self-loop are allowed
* - Adjacency lists store many different copies of the same
* String. You can use less memory by interning the strings.
*
* % java Graph < tinyGraph.txt
* A: B C G H
* B: A C H
* C: A B G
* G: A C
* H: A B
*
* A: B C G H
* B: A C H
* C: A B G
* G: A C
* H: A B
*
******************************************************************************/
/**
* The {@code Graph} class represents an undirected graph of vertices
* with string names.
* It supports the following operations: add an edge, add a vertex,
* get all the vertices, iterate over all the neighbors adjacent
* to a vertex, is there a vertex, is there an edge between two vertices.
* Self-loops are permitted; parallel edges are discarded.
*
* For additional documentation,
* see Section 4.5 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
*/
public class Graph {
// symbol table: key = string vertex, value = set of neighboring vertices
private ST> st;
// number of edges
private int E;
/**
* Initializes an empty graph with no vertices or edges.
*/
public Graph() {
st = new ST>();
}
/**
* Initializes a graph from the specified file, using the specified delimiter.
*
* @param filename the name of the file
* @param delimiter the delimiter
*/
public Graph(String filename, String delimiter) {
st = new ST>();
In in = new In(filename);
while (in.hasNextLine()) {
String line = in.readLine();
String[] names = line.split(delimiter);
for (int i = 1; i < names.length; i++) {
addEdge(names[0], names[i]);
}
}
}
/**
* Returns the number of vertices in this graph.
*
* @return the number of vertices in this graph
*/
public int V() {
return st.size();
}
/**
* Returns the number of edges in this graph.
*
* @return the number of edges in this graph
*/
public int E() {
return E;
}
// throw an exception if v is not a vertex
private void validateVertex(String v) {
if (!hasVertex(v)) throw new IllegalArgumentException(v + " is not a vertex");
}
/**
* Returns the degree of vertex v in this graph.
*
* @param v the vertex
* @return the degree of {@code v} in this graph
* @throws IllegalArgumentException if {@code v} is not a vertex in this graph
*/
public int degree(String v) {
validateVertex(v);
return st.get(v).size();
}
/**
* Adds the edge v-w to this graph (if it is not already an edge).
*
* @param v one vertex in the edge
* @param w the other vertex in the edge
*/
public void addEdge(String v, String w) {
if (!hasVertex(v)) addVertex(v);
if (!hasVertex(w)) addVertex(w);
if (!hasEdge(v, w)) E++;
st.get(v).add(w);
st.get(w).add(v);
}
/**
* Adds vertex v to this graph (if it is not already a vertex).
*
* @param v the vertex
*/
public void addVertex(String v) {
if (!hasVertex(v)) st.put(v, new SET());
}
/**
* Returns the vertices in this graph.
*
* @return the set of vertices in this graph
*/
public Iterable vertices() {
return st.keys();
}
/**
* Returns the set of vertices adjacent to v in this graph.
*
* @param v the vertex
* @return the set of vertices adjacent to vertex {@code v} in this graph
* @throws IllegalArgumentException if {@code v} is not a vertex in this graph
*/
public Iterable adjacentTo(String v) {
validateVertex(v);
return st.get(v);
}
/**
* Returns true if v is a vertex in this graph.
*
* @param v the vertex
* @return {@code true} if {@code v} is a vertex in this graph,
* {@code false} otherwise
*/
public boolean hasVertex(String v) {
return st.contains(v);
}
/**
* Returns true if v-w is an edge in this graph.
*
* @param v one vertex in the edge
* @param w the other vertex in the edge
* @return {@code true} if {@code v-w} is a vertex in this graph,
* {@code false} otherwise
* @throws IllegalArgumentException if either {@code v} or {@code w}
* is not a vertex in this graph
*/
public boolean hasEdge(String v, String w) {
validateVertex(v);
validateVertex(w);
return st.get(v).contains(w);
}
/**
* Returns a string representation of this graph.
*
* @return string representation of this graph
*/
public String toString() {
StringBuilder s = new StringBuilder();
for (String v : st) {
s.append(v + ": ");
for (String w : st.get(v)) {
s.append(w + " ");
}
s.append('\n');
}
return s.toString();
}
/**
* Unit tests the {@code Graph} data type.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {
// create graph
Graph graph = new Graph();
while (!StdIn.isEmpty()) {
String v = StdIn.readString();
String w = StdIn.readString();
graph.addEdge(v, w);
}
// print out graph
StdOut.println(graph);
// print out graph again by iterating over vertices and edges
for (String v : graph.vertices()) {
StdOut.print(v + ": ");
for (String w : graph.adjacentTo(v)) {
StdOut.print(w + " ");
}
StdOut.println();
}
}
}