Initial revision
commit
5dcbf60660
|
@ -0,0 +1,511 @@
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of a mathematical relationship model using Java. It supports<br>
|
||||||
|
* the ability to add and remove items and relationships between the items from the graph<br>
|
||||||
|
* as well as finding various items in the graph using several different algorithms.
|
||||||
|
* @author Andrew Coleman
|
||||||
|
*/
|
||||||
|
public class Graph {
|
||||||
|
//size integer variable to keep track of number of nodes in the graph
|
||||||
|
private int size;
|
||||||
|
//Double two-dimensional array for the adjacency matrix
|
||||||
|
private double[][] adjacent;
|
||||||
|
//Array for holding the movie edges
|
||||||
|
private String[][] movielist;
|
||||||
|
//Array for holding the dates of movies
|
||||||
|
private int[][] datelist;
|
||||||
|
//boolean to determine whether a graph is directed
|
||||||
|
private boolean directed;
|
||||||
|
//Vertex storage list
|
||||||
|
private ArrayList vertexList;
|
||||||
|
//int to determin generic unweighted value
|
||||||
|
private final int UNWEIGHTED_VALUE = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Constructor, creates an undirected graph.
|
||||||
|
*/
|
||||||
|
public Graph () {
|
||||||
|
size = 0;
|
||||||
|
adjacent = new double[size][size];
|
||||||
|
movielist = new String[size][size];
|
||||||
|
datelist = new int[size][size];
|
||||||
|
vertexList = new ArrayList();
|
||||||
|
directed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, takes a boolean to determine directed or undirected.
|
||||||
|
*/
|
||||||
|
public Graph ( boolean param ) {
|
||||||
|
size = 0;
|
||||||
|
adjacent = new double[size][size];
|
||||||
|
movielist = new String[size][size];
|
||||||
|
datelist = new int[size][size];
|
||||||
|
vertexList = new ArrayList();
|
||||||
|
directed = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all vertecies in the graph and sets the size to zero.
|
||||||
|
*/
|
||||||
|
public void makeEmpty() {
|
||||||
|
size = 0;
|
||||||
|
adjacent = new double[size][size];
|
||||||
|
movielist = new String[size][size];
|
||||||
|
datelist = new int[size][size];
|
||||||
|
vertexList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convienence method for determining if the graph is empty.
|
||||||
|
* @return boolean if the graph is empty.
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return ( size == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convienence method for determining the number of vertecies in the graph.
|
||||||
|
* @return int of the size of the graph.pat
|
||||||
|
*/
|
||||||
|
public int numVertices() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the number of edges between all points in the graph.
|
||||||
|
* @return int of the number of edges.
|
||||||
|
*/
|
||||||
|
public int numEdges() {
|
||||||
|
int c = 0;
|
||||||
|
for ( int x = 0; x < size; x++ ) {
|
||||||
|
for ( int y = 0; y < size; y++ ) {
|
||||||
|
if ( adjacent[x][y] != Double.POSITIVE_INFINITY ) {
|
||||||
|
c++; //But wait, it's Java!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to resize the adjacency matrix.
|
||||||
|
* @param Size integer value of the size of the graph.
|
||||||
|
*/
|
||||||
|
private void resizeAdjacent ( int size ) {
|
||||||
|
double[][] temp = new double[size][size];
|
||||||
|
String[][] tmovie = new String[size][size];
|
||||||
|
int[][] tdate = new int[size][size];
|
||||||
|
for( int x = 0; x < size - 1; x++)
|
||||||
|
for ( int y = 0; y < size - 1; y++ ) {
|
||||||
|
temp[x][y] = adjacent[x][y];
|
||||||
|
tmovie[x][y] = movielist[x][y];
|
||||||
|
tdate[x][y] = datelist[x][y];
|
||||||
|
}
|
||||||
|
for ( int x = 0; x < size; x++ ) {
|
||||||
|
temp[x][size - 1] = Double.POSITIVE_INFINITY;
|
||||||
|
temp[size - 1][x] = Double.POSITIVE_INFINITY;
|
||||||
|
tmovie[x][size - 1] = "";
|
||||||
|
tmovie[size - 1][x] = "";
|
||||||
|
tdate[x][size - 1] = 0;
|
||||||
|
tdate[size - 1][x] = 0;
|
||||||
|
}
|
||||||
|
adjacent = temp;
|
||||||
|
movielist = tmovie;
|
||||||
|
datelist = tdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new GraphNode into the graph.
|
||||||
|
* @param GraphNode the node to be added.
|
||||||
|
* @throws GraphException if the node is already in the graph.
|
||||||
|
*/
|
||||||
|
public void addVertex ( GraphNode myItem ) throws GraphException {
|
||||||
|
if ( findIndex ( myItem.getKey() ) >= 0 )
|
||||||
|
throw new GraphException ( "Vertex already exists!" );
|
||||||
|
size++;
|
||||||
|
vertexList.add ( myItem );
|
||||||
|
resizeAdjacent ( vertexList.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an edge with a weight.
|
||||||
|
* @param searchKey1 first vertex to use in the edge.
|
||||||
|
* @param searchKey2 second vertex to use in the edge.
|
||||||
|
* @param weight double value of the edge between searchKey1 and searchKey2.
|
||||||
|
* @throws GraphException if an edge already exists.
|
||||||
|
*/
|
||||||
|
public void addEdge ( Comparable searchKey1, Comparable searchKey2, double weight ) throws GraphException {
|
||||||
|
int x = findIndex ( searchKey1 );
|
||||||
|
int y = findIndex ( searchKey2 );
|
||||||
|
if ( x < 0 || y < 0 )
|
||||||
|
throw new GraphException ( "No matching vertecies were found!" );
|
||||||
|
if ( adjacent[x][y] > 0 )
|
||||||
|
throw new GraphException ( "Edge already exists!" );
|
||||||
|
adjacent[x][y] = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an edge between two actors and also records the name and date of the film connecting the actors.
|
||||||
|
* @param searchKey1 first actor to find.
|
||||||
|
* @param searchKey2 second actor to find.
|
||||||
|
* @param movie movie that both actors starred in.
|
||||||
|
* @param date date of the movie's release.
|
||||||
|
* @throws GraphException if a duplicate was found or if no vertecies were found.
|
||||||
|
*/
|
||||||
|
public void addEdge ( Comparable searchKey1, Comparable searchKey2, String movie, String date ) throws GraphException {
|
||||||
|
int x = findIndex ( searchKey1 );
|
||||||
|
int y = findIndex ( searchKey2 );
|
||||||
|
if ( x < 0 || y < 0 )
|
||||||
|
throw new GraphException ( "No matching vertecies were found!" );
|
||||||
|
int datenum = Integer.parseInt ( date );
|
||||||
|
if ( datenum == 0 || datelist[x][y] < datenum || (datelist[x][y] == datenum && movielist[x][y].compareTo ( movie ) > 0) ) {
|
||||||
|
adjacent[x][y] = UNWEIGHTED_VALUE;
|
||||||
|
adjacent[y][x] = UNWEIGHTED_VALUE;
|
||||||
|
movielist[x][y] = movie;
|
||||||
|
movielist[y][x] = movie;
|
||||||
|
datelist[x][y] = datenum;
|
||||||
|
datelist[y][x] = datenum;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new GraphException ( "Duplicate edge exists!" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an unweighted edge between two keys in the graph.
|
||||||
|
* @param searchKey1 first vertex to find.
|
||||||
|
* @param searchKey2 second vertex to find.
|
||||||
|
* @throws GraphException if a duplicate was found or no matching vertecies found.
|
||||||
|
*/
|
||||||
|
public void addEdge ( Comparable searchKey1, Comparable searchKey2 ) throws GraphException {
|
||||||
|
int x = findIndex ( searchKey1 );
|
||||||
|
int y = findIndex ( searchKey2 );
|
||||||
|
if ( x < 0 || y < 0 )
|
||||||
|
throw new GraphException ( "Vertecies not found!" );
|
||||||
|
if ( adjacent[x][y] > 0 )
|
||||||
|
throw new GraphException ( "Edge already exists!" );
|
||||||
|
adjacent[x][y] = UNWEIGHTED_VALUE;
|
||||||
|
if(!directed) {
|
||||||
|
adjacent[y][x] = UNWEIGHTED_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the edge between two keys in the graph.
|
||||||
|
* @param searchKey1 first vertex to find.
|
||||||
|
* @param searchKey2 second vertex to find.
|
||||||
|
* @throws GraphException if a duplicate was found.
|
||||||
|
*/
|
||||||
|
public double getWeight ( Comparable searchKey1, Comparable searchKey2 ) throws GraphException {
|
||||||
|
int x = findIndex ( searchKey1 );
|
||||||
|
int y = findIndex ( searchKey2 );
|
||||||
|
if ( x < 0 || y < 0 )
|
||||||
|
throw new GraphException ( "Edge does not exist!" );
|
||||||
|
return adjacent[x][y];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the movie connection between two actors.
|
||||||
|
* @param searchKey1 first actor to find.
|
||||||
|
* @param searchKey2 second actor to find.
|
||||||
|
* @return String representing the oldest and first movie alphabetically found to be linking the two actors.
|
||||||
|
* @throws GraphException if no edge was found.
|
||||||
|
*/
|
||||||
|
public String getMovie ( Comparable searchKey1, Comparable searchKey2 ) throws GraphException {
|
||||||
|
int x = findIndex ( searchKey1 );
|
||||||
|
int y = findIndex ( searchKey2 );
|
||||||
|
if ( x < 0 || y < 0 )
|
||||||
|
throw new GraphException ( "Movie connection does not exist!" );
|
||||||
|
return movielist[x][y] + "(" + datelist[x][y] + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a vertex by index.
|
||||||
|
* @param index Integer number representing the vertex you want.
|
||||||
|
* @return GraphNode of the vertex at the specified index.
|
||||||
|
* @throws GraphException if index is out of range ( 1 - size ).
|
||||||
|
*/
|
||||||
|
public GraphNode getVertex ( int index ) throws GraphException {
|
||||||
|
if ( index > size || index < 0 )
|
||||||
|
throw new GraphException ( "Index out of bounds!" );
|
||||||
|
else
|
||||||
|
return (GraphNode)vertexList.get ( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the vertex represented by a searchable key.
|
||||||
|
* @param searchKey vertex to find.
|
||||||
|
* @return GraphNode representing the vertex at key searchKey,
|
||||||
|
* @throws GraphException if vertex is not found,
|
||||||
|
*/
|
||||||
|
public GraphNode getVertex ( Comparable searchKey ) throws GraphException {
|
||||||
|
return getVertex ( findIndex ( searchKey ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the searchable key found at a particular index.
|
||||||
|
* @param index integer index to get the key from.
|
||||||
|
* @return Comparable of the searchable key.
|
||||||
|
* @throws GraphException if the index is out of range.
|
||||||
|
*/
|
||||||
|
public Comparable getSearchKey ( int index ) throws GraphException {
|
||||||
|
if ( index > size || index < 0 )
|
||||||
|
throw new GraphException ( "Index out of range!" );
|
||||||
|
return ((GraphNode)(vertexList.get ( index ))).getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private method for finding the index of a given searchable key.
|
||||||
|
* @param key of the vertex to find in the graph. Assumes to be in the range 1 - size.
|
||||||
|
* @return int representing the index of the vertex or -1 if no vertex is found.
|
||||||
|
*/
|
||||||
|
private int findIndex ( Comparable key ) {
|
||||||
|
for ( int i = 0; i < vertexList.size(); i++ )
|
||||||
|
if ( ((GraphNode)vertexList.get ( i )).getKey().compareTo ( key ) == 0 )
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all vertices, sets all to be unmarked.
|
||||||
|
*/
|
||||||
|
private void clearMarks() {
|
||||||
|
for ( int x = 0; x < size; x++ ) {
|
||||||
|
((GraphNode)vertexList.get ( x )).setMarked ( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an edge between two searchable keys.
|
||||||
|
* @param searchKey1 first vertex to find.
|
||||||
|
* @param searchKey2 second vertex to find.
|
||||||
|
* @throws GraphException if vertecies do not exist.
|
||||||
|
*/
|
||||||
|
public void removeEdge ( Comparable searchKey1, Comparable searchKey2 ) throws GraphException {
|
||||||
|
int a = findIndex ( searchKey1 );
|
||||||
|
int b = findIndex ( searchKey2 );
|
||||||
|
if ( a == -1 || b == -1 ) throw new GraphException ( "Entry not found in list!" );
|
||||||
|
adjacent[a][b] = Double.POSITIVE_INFINITY;
|
||||||
|
movielist[a][b] = "";
|
||||||
|
if ( !directed ) {
|
||||||
|
adjacent[b][a] = Double.POSITIVE_INFINITY;
|
||||||
|
movielist[b][a] = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a vertex by a searchable key.
|
||||||
|
* @param key the vertex to find.
|
||||||
|
* @return GraphNode of the vertex removed from the graph.
|
||||||
|
* @throws GraphException if the vertex is not in the graph.
|
||||||
|
*/
|
||||||
|
public GraphNode removeVertex ( Comparable key ) throws GraphException {
|
||||||
|
int index = findIndex ( key );
|
||||||
|
if ( index == -1 ) throw new GraphException ( "Vertex not in graph!" );
|
||||||
|
double[][] temp = new double[adjacent.length - 1][adjacent.length - 1];
|
||||||
|
String[][] mtemp = new String[adjacent.length - 1][adjacent.length - 1];
|
||||||
|
for ( int row = 0; row < adjacent.length; row++ ) {
|
||||||
|
for ( int col = 0; col < adjacent[0].length; col++ ) {
|
||||||
|
if ( row != index && col != index ) {
|
||||||
|
int newrow = row;
|
||||||
|
int newcol = col;
|
||||||
|
/* make sure the row/col are not in the row/col of the vertex to be removed */
|
||||||
|
if ( row > index ) newrow = row - 1;
|
||||||
|
if ( col > index ) newcol = col - 1;
|
||||||
|
temp[newrow][newcol] = adjacent[row][col];
|
||||||
|
mtemp[newrow][newcol] = movielist[row][col];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
adjacent = temp;
|
||||||
|
movielist = mtemp;
|
||||||
|
size--;
|
||||||
|
return (GraphNode)vertexList.remove ( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the breadth-first traversal of a searchable key.
|
||||||
|
* @param searchKey vertex to start from.
|
||||||
|
* @return ArrayList of the vertecies in the path. Empty if no path is found.
|
||||||
|
*/
|
||||||
|
public ArrayList bft ( Comparable searchKey ) {
|
||||||
|
GraphNode temp;
|
||||||
|
ArrayList searchList = new ArrayList();
|
||||||
|
QueueReferenceBased bfsQueue = new QueueReferenceBased();
|
||||||
|
bfsQueue.enqueue ( vertexList.get ( findIndex ( searchKey ) ) );
|
||||||
|
getVertex ( searchKey ).setMarked ( true );
|
||||||
|
searchList.add ( getVertex ( searchKey ) );
|
||||||
|
|
||||||
|
while ( !bfsQueue.isEmpty() ) {
|
||||||
|
temp = (GraphNode)bfsQueue.dequeue();
|
||||||
|
|
||||||
|
for ( int g = 0; g < size; g++ ) {
|
||||||
|
if ( adjacent[findIndex ( temp.getKey() )][g] != Double.POSITIVE_INFINITY && !getVertex ( g ).isMarked() ) {
|
||||||
|
((GraphNode)vertexList.get ( g )).setMarked ( true );
|
||||||
|
bfsQueue.enqueue ( vertexList.get ( g ) );
|
||||||
|
searchList.add ( getVertex ( g ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearMarks();
|
||||||
|
return searchList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the diameter of the graph, returns infinity if unconnected.
|
||||||
|
* @return int representing the diameter of the graph.
|
||||||
|
*/
|
||||||
|
public double diameter() {
|
||||||
|
double mins[] = new double[size];
|
||||||
|
for ( int x = 0; x < size; x++ ) {
|
||||||
|
mins[x] = 0;
|
||||||
|
ArrayList t = bft ( getVertex ( x ).getKey() );
|
||||||
|
if ( t.size() != size ) return Double.POSITIVE_INFINITY;
|
||||||
|
for ( int y = 1; y < t.size(); y++ ) {
|
||||||
|
mins[x] += getWeight ( ((GraphNode) t.get ( y - 1 )).getKey(), ((GraphNode) t.get ( y )).getKey() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double minsize = mins[0];
|
||||||
|
for ( int x = 0; x < size; x++ ) {
|
||||||
|
if ( minsize > mins[x] )
|
||||||
|
minsize = mins[x];
|
||||||
|
}
|
||||||
|
return minsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a breadth-first search between two searchable keys.
|
||||||
|
* @param searchKey1 first key to find.
|
||||||
|
* @param searchKey2 second key to find.
|
||||||
|
* @return ArrayList containing the path between the two keys, empty if no path is possible.
|
||||||
|
*/
|
||||||
|
public ArrayList bfs ( Comparable searchKey1, Comparable searchKey2 ) {
|
||||||
|
ArrayList p = bft ( searchKey1 );
|
||||||
|
Comparable curkey = searchKey1;
|
||||||
|
int x = 0;
|
||||||
|
for ( x = 0; x < p.size() && curkey.compareTo ( searchKey2 ) != 0; x++ )
|
||||||
|
curkey = ((GraphNode) p.get ( x )).getKey();
|
||||||
|
|
||||||
|
if ( x > p.size() / 2 ) {
|
||||||
|
for ( int y = p.size() - 1; y > x; y-- )
|
||||||
|
p.remove( y );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ArrayList q = new ArrayList ( x );
|
||||||
|
for ( int y = 0; y < x; y++ )
|
||||||
|
q.add ( p.get ( x ) );
|
||||||
|
p = q;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a depth-first search for a searchable key.
|
||||||
|
* @param searchKey vertex to find.
|
||||||
|
* @return ArrayList containing the path to the vertex.
|
||||||
|
* @throws GraphException if no path is found.
|
||||||
|
*/
|
||||||
|
public ArrayList dfs ( Comparable searchKey ) throws GraphException {
|
||||||
|
ArrayList dfsList = new ArrayList();
|
||||||
|
dfsList = dfsRec ( getVertex ( searchKey ), dfsList );
|
||||||
|
clearMarks();
|
||||||
|
if ( dfsList.isEmpty() ) {
|
||||||
|
throw new GraphException ( "No path is found!" );
|
||||||
|
}
|
||||||
|
return dfsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private recursive method called to generate a breadth-first search.
|
||||||
|
* @param vertex GraphNode to search from.
|
||||||
|
* @param searchRecList list to use while recursing.
|
||||||
|
* @return ArrayList of the generated path.
|
||||||
|
*/
|
||||||
|
private ArrayList dfsRec ( GraphNode vertex, ArrayList searchRecList ) {
|
||||||
|
searchRecList.add ( vertex );
|
||||||
|
vertex.setMarked ( true );
|
||||||
|
int i = vertexList.indexOf ( vertex );
|
||||||
|
for ( int j = 0; j<size; j++ ) {
|
||||||
|
if ( adjacent[i][j] != Double.POSITIVE_INFINITY && !(getVertex ( j )).isMarked() )
|
||||||
|
dfsRec( getVertex ( j ), searchRecList );
|
||||||
|
}
|
||||||
|
return searchRecList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to calculate the shortest distance between two vertices using Djisktra's algorithm.
|
||||||
|
* @throws GraphException if both Comparables are equal or there is no connecting path.
|
||||||
|
* @return ArrayList containing the path between the two items in the Graph.
|
||||||
|
*/
|
||||||
|
public ArrayList shortestPath ( Comparable firstkey, Comparable lastkey ) throws GraphException {
|
||||||
|
if ( firstkey.compareTo ( lastkey ) == 0 )
|
||||||
|
throw new GraphException ( "Cannot find shortest path to same vertex!" );
|
||||||
|
/* the arraylist containing the raw path array */
|
||||||
|
ArrayList path = new ArrayList ( vertexList.size() );
|
||||||
|
/* mark the first vertex */
|
||||||
|
getVertex ( firstkey ).setMarked ( true );
|
||||||
|
/* indexes of the first and last search keys */
|
||||||
|
int firstindex = findIndex ( firstkey );
|
||||||
|
int secondindex = findIndex ( lastkey );
|
||||||
|
/* the row of the adjacency matrix at firstindex */
|
||||||
|
double[] weight = new double[vertexList.size()];
|
||||||
|
/* initialize the weight/path arrays */
|
||||||
|
for ( int i = 0; i < weight.length; i++ ) {
|
||||||
|
path.add ( vertexList.get ( i ) );
|
||||||
|
weight[i] = adjacent[firstindex][i];
|
||||||
|
/* if the weight is not infinity we must change the path to reflect the changes */
|
||||||
|
if ( weight[i] < Double.POSITIVE_INFINITY )
|
||||||
|
path.set ( i, getVertex ( firstkey ) );
|
||||||
|
}
|
||||||
|
/* loop through all the elements in the graph, must mark them all */
|
||||||
|
for ( int i = 1; i < vertexList.size(); i++ ) {
|
||||||
|
/* index of smallest vertex */
|
||||||
|
int smallest = -1;
|
||||||
|
/* smallest weight thus far that is not marked */
|
||||||
|
double smallestweight = Double.POSITIVE_INFINITY;
|
||||||
|
for ( int j = 0; j < weight.length; j++ )
|
||||||
|
/* run through the weight array and find the smallest weight */
|
||||||
|
if ( smallestweight >= weight[j] && !((GraphNode)vertexList.get ( j )).isMarked() ) {
|
||||||
|
/* note smallest vertex */
|
||||||
|
smallest = j;
|
||||||
|
smallestweight = weight[j];
|
||||||
|
}
|
||||||
|
/* mark smallest vertex */
|
||||||
|
GraphNode smallnode = (GraphNode)vertexList.get ( smallest );
|
||||||
|
smallnode.setMarked ( true );
|
||||||
|
/* update the weight/path arrays */
|
||||||
|
for ( int j = 0; j < weight.length; j++ )
|
||||||
|
/* if a new weight to that vertex is less than the current weight, change the weight in the array and change the path arraylist */
|
||||||
|
if ( weight[j] > weight[smallest] + adjacent[smallest][j] ) {
|
||||||
|
weight[j] = weight[smallest] + adjacent[smallest][j];
|
||||||
|
path.set ( j, vertexList.get ( smallest ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* backwards path */
|
||||||
|
ArrayList result = new ArrayList();
|
||||||
|
GraphNode node = getVertex ( lastkey );
|
||||||
|
int lastindex = findIndex ( lastkey );
|
||||||
|
/* while the node is not the first node */
|
||||||
|
while ( lastindex != firstindex ) {
|
||||||
|
result.add ( node );
|
||||||
|
node = (GraphNode)path.get ( lastindex );
|
||||||
|
int newlastindex = findIndex ( node.getKey() );
|
||||||
|
/* if the indexes are the same, then there is no way to get to that vertex */
|
||||||
|
if ( newlastindex == lastindex )
|
||||||
|
throw new GraphException ( "No connecting path!" );
|
||||||
|
else
|
||||||
|
lastindex = newlastindex;
|
||||||
|
}
|
||||||
|
/* gotta add the first one */
|
||||||
|
result.add ( getVertex ( firstkey ) );
|
||||||
|
|
||||||
|
/* reverse the arraylist */
|
||||||
|
path.clear();
|
||||||
|
for ( int i = result.size() - 1; i >= 0; i-- )
|
||||||
|
path.add ( result.get ( i ) );
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Coleman
|
||||||
|
* This class provides a wrapper for the Graph object and parses all input files.
|
||||||
|
*/
|
||||||
|
public class GraphDriver {
|
||||||
|
|
||||||
|
// only need one graph
|
||||||
|
private static Graph mygraph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a path of actors from an ArrayList.
|
||||||
|
* @param path An ArrayList returned from shortestPath or the like.
|
||||||
|
*/
|
||||||
|
private static void printPath ( ArrayList path ) {
|
||||||
|
for ( int x = 0; x < path.size() - 1; x++ ) {
|
||||||
|
Comparable one = ((GraphNode)path.get ( x )).getKey();
|
||||||
|
Comparable two = ((GraphNode)path.get ( x + 1 )).getKey();
|
||||||
|
String movie = mygraph.getMovie ( one, two );
|
||||||
|
System.out.println ( one.toString() + " starred with " + two.toString() + " in the movie " + movie );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a path of actors from an ArrayList.
|
||||||
|
* @param path An ArrayList returned from shortestPath or the like.
|
||||||
|
*/
|
||||||
|
private static void printPathToo ( ArrayList path ) {
|
||||||
|
for ( int x = 0; x < path.size() - 1; x++ ) {
|
||||||
|
System.out.print ( ((GraphNode)path.get ( x )).getKey() );
|
||||||
|
if ( x != path.size() - 2 )
|
||||||
|
System.out.print ( ", " );
|
||||||
|
else
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and inserts all data from an input file.
|
||||||
|
* @param filename Name of the file to be read.
|
||||||
|
* @param filenum Number of the file in the sequence, can be -1 if not known.
|
||||||
|
* @param len Total number of input files.
|
||||||
|
*/
|
||||||
|
private static void readFile ( String filename, int filenum, int len ) {
|
||||||
|
BufferedReader read = null;
|
||||||
|
ArrayList actors = new ArrayList();
|
||||||
|
try {
|
||||||
|
String t = "";
|
||||||
|
if ( filenum != -1 ) {
|
||||||
|
t = " (" + (filenum + 1) + "/" + len + ")";
|
||||||
|
}
|
||||||
|
System.out.println ( "***Reading from file: " + filename + t );
|
||||||
|
read = new BufferedReader ( new FileReader ( filename ) );
|
||||||
|
//this big loop reads in the movie name and all the actors
|
||||||
|
while ( read.ready() ) {
|
||||||
|
String line = read.readLine();
|
||||||
|
if ( line.equals ( "" ) ) continue;
|
||||||
|
//split the date off the movie name, makes for easier tie breaking.
|
||||||
|
String data[] = line.split ( "\\(\\d{4}\\)\\s*$" );
|
||||||
|
String date = line.substring ( data[0].length() + 1, data[0].length() + 5 );
|
||||||
|
data[0].trim();
|
||||||
|
|
||||||
|
//get all the actors in a usable form
|
||||||
|
line = read.readLine();
|
||||||
|
while ( !line.equals ( "" ) ) {
|
||||||
|
actors.add ( line );
|
||||||
|
line = read.readLine();
|
||||||
|
}
|
||||||
|
String actor[] = new String[actors.size()];
|
||||||
|
actor = (String [])actors.toArray ( actor );
|
||||||
|
//now we must add all the actors into the graph
|
||||||
|
for ( int x = 0; x < actor.length; x++ ) {
|
||||||
|
try {
|
||||||
|
mygraph.addVertex ( new GraphNode ( actor[x] ) );
|
||||||
|
}
|
||||||
|
catch ( GraphException exception ) {}
|
||||||
|
}
|
||||||
|
//and add an edge between all the actors for this movie
|
||||||
|
for ( int x = 0; x < actor.length - 1; x++ ) {
|
||||||
|
for ( int y = x + 1; y < actor.length; y++ ) {
|
||||||
|
try {
|
||||||
|
mygraph.addEdge ( actor[x], actor[y], data[0], date );
|
||||||
|
}
|
||||||
|
catch ( GraphException exception ) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//start all over again
|
||||||
|
actors.clear();
|
||||||
|
}// end while
|
||||||
|
}
|
||||||
|
catch ( IOException exception ) {
|
||||||
|
System.out.println ( "Error reading the file: " + filename );
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main ( String[] args ) {
|
||||||
|
if ( args.length < 1 ) {
|
||||||
|
System.out.println ( "Usage: java GraphDriver [input files]" );
|
||||||
|
System.exit ( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
mygraph = new Graph();
|
||||||
|
|
||||||
|
for ( int filenum = 0; filenum < args.length; filenum++ ) {
|
||||||
|
readFile ( args[filenum], filenum, args.length );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this block is the user interface. it is simple, but yet still allows for all
|
||||||
|
* the neccessary functionality of the project.
|
||||||
|
*/
|
||||||
|
String command = "";
|
||||||
|
while ( !command.equals ( "quit" ) ) {
|
||||||
|
System.out.println ( "*Commands*\t*Description*" );
|
||||||
|
System.out.println ( "path\t\tDjikstra's Shortest Path" );
|
||||||
|
System.out.println ( "bfs\t\tBreadth-First Search" );
|
||||||
|
System.out.println ( "add\t\tUpdate Graph From File" );
|
||||||
|
System.out.println ( "dia\t\tCompute Diameter Of Graph" );
|
||||||
|
System.out.println ( "quit\t\tQuit" );
|
||||||
|
System.out.print ( "> " );
|
||||||
|
BufferedReader in = new BufferedReader ( new InputStreamReader ( System.in ) );
|
||||||
|
try {
|
||||||
|
command = in.readLine().trim();
|
||||||
|
}
|
||||||
|
catch ( IOException exception ) {
|
||||||
|
System.out.println ( "bailing from:" );
|
||||||
|
exception.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( command.equals( "path" ) ) {
|
||||||
|
System.out.print ( "actors (one,two)> " );
|
||||||
|
String actors[] = null;
|
||||||
|
try {
|
||||||
|
actors = (String [])in.readLine().trim().split ( "," );
|
||||||
|
}
|
||||||
|
catch ( IOException exception ) {
|
||||||
|
System.out.println ( "bailing from:" );
|
||||||
|
exception.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( actors.length != 2 ) {
|
||||||
|
System.out.println ( "Enter two actors only!" );
|
||||||
|
}
|
||||||
|
ArrayList path = mygraph.shortestPath ( actors[0].trim(), actors[1].trim() );
|
||||||
|
printPath ( path );
|
||||||
|
}
|
||||||
|
else if ( command.equals( "bfs" ) ) {
|
||||||
|
System.out.print ( "actors (one,two)> " );
|
||||||
|
String actors[] = null;
|
||||||
|
try {
|
||||||
|
actors = (String [])in.readLine().trim().split ( "," );
|
||||||
|
}
|
||||||
|
catch ( IOException exception ) {
|
||||||
|
System.out.println ( "bailing from:" );
|
||||||
|
exception.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( actors.length != 2 ) {
|
||||||
|
System.out.println ( "Enter two actors only!" );
|
||||||
|
}
|
||||||
|
//put in real bfs here for two states
|
||||||
|
ArrayList path = mygraph.bfs ( actors[0].trim(), actors[1].trim() );
|
||||||
|
printPathToo ( path );
|
||||||
|
}
|
||||||
|
else if ( command.equals ( "add" ) ) {
|
||||||
|
System.out.print ( "read from file> " );
|
||||||
|
String filename[] = null;
|
||||||
|
try {
|
||||||
|
filename = (String [])in.readLine().trim().split ( " " );
|
||||||
|
}
|
||||||
|
catch ( IOException exception ) {
|
||||||
|
System.out.println ( "bailing from:" );
|
||||||
|
exception.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for ( int q = 0; q < filename.length; q++ ) {
|
||||||
|
readFile ( filename[q], q, filename.length );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( command.equals ( "dia" ) ) {
|
||||||
|
System.out.println ( "Please wait while searching through " + mygraph.numVertices() + " vertecies..." );
|
||||||
|
System.out.println ( "The diameter of the graph is " + mygraph.diameter() );
|
||||||
|
}
|
||||||
|
else if ( command.equals ( "quit" ) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* @author Coleman
|
||||||
|
* This class provides an exception for handling errors within the graph.
|
||||||
|
*/
|
||||||
|
public class GraphException extends RuntimeException {
|
||||||
|
public GraphException ( String s ) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* @author Andrew Coleman
|
||||||
|
* GraphNode is an object representing a state or item in a tree. Allows for one unique searchable key to identify the vertex.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class GraphNode extends KeyedItem
|
||||||
|
{
|
||||||
|
//the current state of this vertex
|
||||||
|
private boolean mark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, makes a new GraphNode.
|
||||||
|
* @param item A Comparable for the unique searchable key of this vertex.
|
||||||
|
*/
|
||||||
|
GraphNode ( Comparable item ) {
|
||||||
|
super ( item );
|
||||||
|
mark = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if node is marked, false if it is not.
|
||||||
|
* @return A boolean of the current GraphNode's state.
|
||||||
|
*/
|
||||||
|
public boolean isMarked() {
|
||||||
|
return mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets value of mark to true or false.
|
||||||
|
* @param boolean State of the current vertex.
|
||||||
|
*/
|
||||||
|
public void setMarked ( boolean setbool ) {
|
||||||
|
mark = setbool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows for the comparison of two GraphNode objects.
|
||||||
|
* @param node A GraphNode to be compared against the current object.
|
||||||
|
* @return Returns a boolean indicating if the two GraphNodes are equal.
|
||||||
|
*/
|
||||||
|
public boolean equals ( GraphNode node ) {
|
||||||
|
return ( node.getKey().compareTo ( this.getKey() ) == 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
//given to me from mark boshart
|
||||||
|
public abstract class KeyedItem
|
||||||
|
{
|
||||||
|
private Comparable searchKey;
|
||||||
|
|
||||||
|
public KeyedItem(Comparable key)
|
||||||
|
{
|
||||||
|
searchKey = key;
|
||||||
|
} // end constructor
|
||||||
|
|
||||||
|
public Comparable getKey()
|
||||||
|
{
|
||||||
|
return searchKey;
|
||||||
|
} // end getKey
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return searchKey.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue