Initial revision

master
mercury 2003-12-03 17:38:51 +00:00
commit a65c19be29
15 changed files with 1390 additions and 0 deletions

BIN
ClearGraph.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

535
Graph.java Normal file
View File

@ -0,0 +1,535 @@
import java.util.*;
import java.text.DecimalFormat;
import java.awt.Color;
import java.awt.Graphics;
/**
* Graph.java, models graph management and creation.<br>
* Implements: GraphInterface.<br>
* @author <A HREF="mailto:mem1780@tntech.edu">Matt Markham</A><BR>
*/
public class Graph implements GraphInterface
{
//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;
//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;
//temporary Arraylist for dfs
private ArrayList tempAL=new ArrayList();
//ArrayList containing the current shortest path
private ArrayList path;
/**
* Default Constructor, creates an undirected graph.<br>
*/
public Graph ()
{
size = 0;
adjacent = new double[size][size];
vertexList = new ArrayList();
directed=false;
path = new ArrayList();
}
/**
* Constructor, takes a boolean to determine directed or undirected.<br>
*/
public Graph (boolean param)
{
size = 0;
adjacent = new double[size][size];
vertexList = new ArrayList();
directed=param;
path = new ArrayList();
}
public void makeEmpty()
{
size=0;
adjacent = new double[size][size];
vertexList.clear();
}
public boolean isEmpty()
{
return (size==0);
}
public int numVertices()
{
return size;
}
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++; //Insert nerdy joke here
}
}
}
return c;
}
public void addVertex (GraphNode myItem) throws GraphException
{
for(int a=0; a<vertexList.size();a++)
if ( ((GraphNode) vertexList.get(a)).getKey().compareTo ( myItem.getKey() ) == 0 )
throw new GraphException ( "Duplicate entry" );
size++;
vertexList.add(myItem);
resizeAdjacent ( vertexList.size() );
}
/**
* Method to resize the adjacency matrix.<br>
* Preconditions: must be passed a new size value.<br>
* Postconditions: resizes adjacency matrix.<br>
* Throws: None.
*/
private void resizeAdjacent ( int size )
{
double[][] temp = new double[size][size];
for( int x = 0; x < size - 1; x++)
for ( int y = 0; y < size - 1; y++ )
temp[x][y] = adjacent[x][y];
for ( int x = 0; x < size; x++ )
{
temp[x][size - 1] = Double.POSITIVE_INFINITY;
temp[size - 1][x] = Double.POSITIVE_INFINITY;
}
adjacent = temp;
}
public void addEdge(Comparable searchKey1, Comparable searchKey2, double weight) throws GraphException
{
for(int x=0; x<size; x++)
{
if ( ((GraphNode) vertexList.get(x)).getKey().compareTo(searchKey1) == 0 )
{
for(int y=0; y<size;y++)
{
if ( ((GraphNode) vertexList.get(y)).getKey().compareTo(searchKey2) == 0 )
{
adjacent[x][y]=weight;
return;
}//end if get(y)
}// end for y
}//end if get(x)
}//end for x
throw new GraphException ( "Duplicate found!" );
}
public void addEdge(Comparable searchKey1, Comparable searchKey2) throws GraphException
{
for(int x=0; x<size; x++)
{
if ( ((GraphNode) vertexList.get(x)).getKey().compareTo(searchKey1) == 0 )
{
for(int y=0; y<size;y++)
{
if ( ((GraphNode) vertexList.get(y)).getKey().compareTo(searchKey2) == 0 )
{
adjacent[x][y]=UNWEIGHTED_VALUE;
if(!directed)
{adjacent[y][x]=UNWEIGHTED_VALUE;}
return;
}//end if get(y)
}// end for y
}//end if get(x)
}//end for x
throw new GraphException ( "Duplicate found!" );
}
public double getWeight(Comparable searchKey1, Comparable searchKey2) throws GraphException
{
for(int x=0; x<size;x++)
{
if ( ((GraphNode) vertexList.get(x)).getKey().compareTo(searchKey1) == 0 )
{
for(int y=0; y<size;y++)
{
if ( ((GraphNode) vertexList.get(y)).getKey().compareTo(searchKey2) == 0 )
{
return adjacent[x][y];
}//end if get(y)
}// end for y
}//end if get(x)
}//end for x
throw new GraphException ( "Edge does not exist!");
}
public GraphNode getVertex(int index) throws GraphException
{
if (index>size)
throw new GraphException ("index out of bounds!");
else
return (GraphNode)vertexList.get(index);
}
public GraphNode getVertex(Comparable searchKey) throws GraphException
{
for (int x=0;x<vertexList.size();x++)
{
if ( ((GraphNode) vertexList.get(x)).getKey().compareTo(searchKey) == 0)
{
return (GraphNode) vertexList.get(x);
}
}
throw new GraphException ("Vertex not Found in List!");
}
/**
* FInds the index of a given searchKey.<br>
* Preconditions: Must be passed searchKey.<br>
* Postconditions: returns integer index of given searchKey.<br>
* Throws:Nonde.
*/
private int findVertex (Comparable searchKey)
{
for (int d=0; d<size;d++)
{
if ( ((GraphNode) vertexList.get(d)).getKey().compareTo(searchKey) == 0 )
{ return d; }
}
return -1;
}
/**
* Clears all vertices, sets all to be unmarked.<br>
* Preconditions: None.<br>
* Postconditions: Makes all vertices unmarked.<br>
* Throws:None.
*/
private void clearMarks()
{
for (int x=0;x<size;x++)
{
((GraphNode) vertexList.get(x)).setMarked(false);
}
}
public Comparable getSearchKey (int index)
{
return ((GraphNode)(vertexList.get(index))).getKey();
}
public void removeEdge(Comparable searchKey1, Comparable searchKey2) throws GraphException
{
int a=findVertex(searchKey1);
int b=findVertex(searchKey2);
if (a==-1 || b==-1)
throw new GraphException ("Entry not found in list!");
adjacent[a][b]=Double.POSITIVE_INFINITY;
}
public ArrayList bfs (Comparable searchKey) throws GraphException
{
GraphNode temp;
ArrayList searchList = new ArrayList();
QueueReferenceBased bfsQueue= new QueueReferenceBased();
bfsQueue.enqueue(vertexList.get(findVertex(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[findVertex(temp.getKey())][g] != Double.POSITIVE_INFINITY && !getVertex(g).isMarked())
{
((GraphNode)vertexList.get(g)).setMarked(true);
bfsQueue.enqueue(vertexList.get(g));
searchList.add(getVertex(g));
}//end if
}//end for
}//end while
clearMarks();
return searchList;
}
public GraphNode removeVertex ( Comparable key ) throws GraphException
{
int index = -1;
for ( int i = 0; i < vertexList.size(); i++ )
if ( ((GraphNode) vertexList.get ( i )).getKey().compareTo ( key ) == 0 )
index = i;
if ( index == -1 )
throw new GraphException ( "Vertex not in graph" );
double[][] temp = new double[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];
}
}
}
adjacent = temp;
size--;
return (GraphNode) vertexList.remove ( index );
}
public ArrayList dfs (Comparable searchKey) throws GraphException
{
ArrayList dfsList = new ArrayList();
dfsList=dfsRec(getVertex(searchKey), dfsList);
clearMarks();
return dfsList;
}
/**
* Private recursive method called to generate a breadth-first search.<br>
* Preconditions: Must be passed a graphNode and an ArrayList.<br>
* Postconditions: Returns an Arraylist for the bfs.<br>
* Throws:None.
*/
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 );
}//end for j
return searchRecList;
}
/**
* Draws the panel with all of the edges and vertices. <BR>
* Preconditions: A Graphics object and the radius of the vertecies. <BR>
* Postconditions: Draws all of the neccessary components onto the GraphScreen. <BR>
* @author <A HREF="mailto:arc4472@tntech.edu">Andrew Coleman</A><BR>
*/
public void draw ( Graphics g, int radius )
{
/* draw all of the edges in orange */
g.setColor ( Color.orange );
for ( int i = 0; i < adjacent.length; i++ )
{
int firstx = getVertex ( i ).getX();
int firsty = getVertex ( i ).getY();
String firstkey = getVertex ( i ).getKey().toString();
for ( int j = 0; j < adjacent[i].length; j++ )
{
if ( adjacent[i][j] != Double.POSITIVE_INFINITY )
{
int secondx = ((GraphNode) getVertex ( j )).getX();
int secondy = ((GraphNode) getVertex ( j )).getY();
String secondkey = (String)((GraphNode) getVertex ( j )).getKey();
DecimalFormat format = new DecimalFormat();
format.setMaximumFractionDigits ( 3 );
int difference = 10;
/* the final x and y coordinates for the string for each edge */
int xcoord, ycoord;
if ( firstx < secondx )
xcoord = (secondx - firstx) / 2 + firstx;
else
xcoord = (firstx - secondx) / 2 + secondx;
if ( firsty < secondy )
ycoord = (secondy - firsty) / 2 + firsty;
else
ycoord = (firsty - secondy) / 2 + secondy;
/* if i < j, then the edge goes from j to i */
if ( i < j )
{
g.drawLine ( firstx, firsty - 10, secondx, secondy - 10 );
g.drawString ( firstkey + " to " + secondkey + ", Weight: " + format.format ( adjacent[i][j] ), xcoord, ycoord - 11 );
}
/* if i > j, then the edge goes from i to j */
else if ( i > j )
{
g.drawLine ( firstx, firsty + 10, secondx, secondy + 10 );
g.drawString ( firstkey + " to " + secondkey + ", Weight: " + format.format ( adjacent[i][j] ), xcoord, ycoord + 11 );
}
}
}
}
/* draw the shortest path stored in green */
g.setColor ( Color.green );
for ( int i = 1; i < path.size(); i++ )
{
int firstx = ((GraphNode) path.get ( i - 1 )).getX();
int firsty = ((GraphNode) path.get ( i - 1 )).getY();
int secondx = ((GraphNode) path.get ( i )).getX();
int secondy = ((GraphNode) path.get ( i )).getY();
g.drawLine ( firstx, firsty, secondx, secondy );
}
/* draw all of the vertices in dark gray with a light gray border and the comparable data in the middle */
for ( int i = 0; i < numVertices(); i++ )
{
g.setColor ( Color.lightGray );
GraphNode temp = getVertex ( i );
g.fillOval ( temp.getX() - radius, temp.getY() - radius, radius * 2, radius * 2 );
g.setColor ( Color.darkGray );
int difference = 2;
g.fillOval ( temp.getX() - radius + difference, temp.getY() - radius + difference, (radius - difference) * 2, (radius - difference) * 2 );
g.setColor ( Color.white );
g.drawString ( (String) temp.getKey(), temp.getX(), temp.getY() );
}
}
/**
* This method is used to set the arraylist containing the shortest path to be displayed. <BR>
* Preconditions: An arraylist containing a valid shortest path. <BR>
* Postconditions: Sets the current path to the given arraylist. <BR>
* @author <A HREF="mailto:arc4472@tntech.edu">Andrew Coleman</A><BR>
*/
public void setShortestPathDisplay ( ArrayList path )
{
this.path = path;
}
/**
* Used to calculate the shortest distance between two vertices using Djisktra's algorithm. <BR>
* Preconditions: Two comparables representing the data in the two vertices. <BR>
* Postconditions: Returns an ArrayList containing the GraphNodes in the path. <BR>
* Throws: Throws a GraphException if the comparables are the same or there is no connecting path. <BR>
* @author <A HREF="mailto:arc4472@tntech.edu">Andrew Coleman</A><BR>
*/
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 ) );
/* the result to return */
ArrayList sortedresult = new ArrayList ( result.size() );
/* reverse the arraylist */
for ( int i = result.size() - 1; i >= 0; i-- )
sortedresult.add ( result.get ( i ) );
return sortedresult;
}
/**
* This method finds the index of a given comparable object. <BR>
* Preconditions: A valid comparable key in the graph. <BR>
* Postcondtions: Returns the index of the key, or -1 if the key is not in the graph. <BR>
*/
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;
}
}

28
GraphDriver.java Normal file
View File

@ -0,0 +1,28 @@
import java.util.ArrayList;
public class GraphDriver
{
public static void main ( String[] args )
{
Graph mygraph = new Graph();
mygraph.addVertex ( new GraphNode ( "A" ) );
mygraph.addVertex ( new GraphNode ( "B" ) );
mygraph.addVertex ( new GraphNode ( "C" ) );
mygraph.addVertex ( new GraphNode ( "D" ) );
mygraph.addVertex ( new GraphNode ( "E" ) );
mygraph.addEdge ( "A", "D", 9.0 );
mygraph.addEdge ( "A", "B", 8.0 );
mygraph.addEdge ( "A", "E", 4.0 );
mygraph.addEdge ( "B", "C", 1.0 );
mygraph.addEdge ( "C", "B", 2.0 );
mygraph.addEdge ( "C", "D", 3.0 );
mygraph.addEdge ( "D", "C", 2.0 );
mygraph.addEdge ( "D", "E", 7.0 );
mygraph.addEdge ( "E", "C", 1.0 );
ArrayList bft = mygraph.shortestPath ( "A", "C" );
for ( int i = 0; i < bft.size(); i++ )
System.out.println ( bft.get ( i ).toString() );
}
}

11
GraphException.java Normal file
View File

@ -0,0 +1,11 @@
public class GraphException extends RuntimeException
{
public GraphException()
{
} // end default constructor
public GraphException(String s)
{
super(s);
} // end constructor
} // end GraphException

93
GraphGUI.java Normal file
View File

@ -0,0 +1,93 @@
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
/** This is the parent window in the graph, it only sets flags based on menu choices and provides a place for the GraphScreen to draw itself */
public class GraphGUI extends JFrame {
/** the height of the frame */
private final int HEIGHT = 550;
/** the width of the frame */
private final int WIDTH = 640;
/** the JPanel that does all of the work */
private GraphScreen graphscreen;
/** the status bar */
private JLabel information;
/**
* The default constructor. <BR>
* Preconditions: None. <BR>
* Postconditions: Sets up the window and displays everything. <BR>
*/
public GraphGUI() {
super ( "GraphGUI" );
setSize ( WIDTH, HEIGHT );
getContentPane().setLayout ( new BorderLayout() );
addWindowListener ( new WindowAdapter() {
public void windowClosing ( WindowEvent event ) {
System.exit ( 0 );
}
});
/* Center the window in the middle of the screen */
Dimension screensize = getToolkit().getScreenSize();
int screenwidth = screensize.width;
int screenheight = screensize.height;
setLocation ( screenwidth / 2 - WIDTH / 2, screenheight / 2 - HEIGHT / 2);
/* These are the individual menu items in the menu bar. */
JMenuItem cleargraph = new JMenuItem ( new ImageIcon ( "ClearGraph.jpg" ) );
cleargraph.setBackground ( Color.black );
cleargraph.setToolTipText ( "Makes a new, empty, pretty graph." );
cleargraph.addActionListener ( new ActionListener() {
public void actionPerformed ( ActionEvent event ) {
graphscreen.clearGraph();
}
});
JMenuItem shortestpath = new JMenuItem ( new ImageIcon ( "ShortestPath.jpg" ) );
shortestpath.setBackground ( Color.black );
shortestpath.setToolTipText ( "Determines the shortest path between two vertices." );
shortestpath.addActionListener ( new ActionListener() {
public void actionPerformed ( ActionEvent event ) {
graphscreen.findShortestPath();
}
});
JMenuItem quit = new JMenuItem ( new ImageIcon ( "Quit.jpg" ) );
quit.setBackground ( Color.black );
quit.setToolTipText ( "All your base are belong to us." );
quit.addActionListener ( new ActionListener() {
public void actionPerformed ( ActionEvent event ) {
System.exit ( 0 );
}
});
/* the menu that keeps the menuitems */
JMenu graph = new JMenu ( "GraphGUI" );
graph.add ( cleargraph );
graph.add ( shortestpath );
graph.add ( quit );
JMenuBar toolbar = new JMenuBar();
toolbar.add ( graph );
setJMenuBar ( toolbar );
/* set up the two remaining graphical components */
information = new JLabel ( "Ready" );
graphscreen = new GraphScreen ( information );
getContentPane().add ( graphscreen, BorderLayout.CENTER );
getContentPane().add ( information, BorderLayout.SOUTH );
setResizable ( false );
setVisible ( true );
}
/** Start the party */
public static void main ( String[] args ) {
GraphGUI mygraph = new GraphGUI();
}
}

142
GraphInterface.java Normal file
View File

@ -0,0 +1,142 @@
import java.util.*;
public interface GraphInterface
{
//two constructors
//default constructor makes a directed graph
//constructor that takes a boolean (true for directed)
/**
* Makes the current graph empty.<br>
* Preconditions: None.<br>
* Postconditions: makes graph empty.<br>
* Throws: None.
*/
public void makeEmpty();
/**
* Indicates if graph is empty.<br>
* Preconditions: None.<br>
* Postconditions: returns boolean true if graph is empty, false if not.<br>
* Throws: None.
*/
public boolean isEmpty();
/**
* Returns an integer corresponding to thenumber of vertices in the graph.<br>
* Preconditions: None.<br>
* Postconditions: returns int.<br>
* THrows: None.
*/
public int numVertices();
/**
* Returns an integer corresponding to the numberof edges in the graph.<br>
* Preconditions: None.<br>
* Postconditions: returns int.<br>
* Throws: NOne.
*/
public int numEdges();
/**
* Adds a vertex to the graph.<br>
* Preconditions: Must be passed GraphNode to be inserted into the graph.<br>
* Postconditions: Adds the passed-in node to the graph.<br>
* Throws: None.
*/
//add a vertex to the Graph
public void addVertex(GraphNode myItem) throws GraphException;
/**
*Adds an edge to the Graph.<br>
*Preconditions: must be passed the searchkeys of the nodes that are to be connected.<br>
*Postconditions: adds edge to graph.<br>
*Throws: GraphException if searchkeys don't exist.
*/
public void addEdge(Comparable searchKey1, Comparable searchKey2) throws GraphException;
/**
* Adds a weighted edge to the graph.<br>
* Preconditions: must be passed two search keys and a weight.<br>
* Postconditions: adds weighted edge to the graph.<br>
* Throws: GraphException if given invalid endpoints or weight value
*/
public void addEdge(Comparable searchKey1, Comparable searchKey2, double weight) throws GraphException;
/**
* Retrieves the weight of a given edge. <br>
* Preconditions: must be given searchkeys of the endpoints of the edge.<br>
* Postconditions: returns double value for the weight.<br>
* Throws: GraphException if given invalid endpoints.
*/
public double getWeight(Comparable searchKey1, Comparable searchKey2) throws GraphException;
/**
* Removes an edge from the graph.<br>
* Preconditions: must be passed searchKey valued for edge's endpoints.<br>
* Postconditions: removes edge from graph.<br>
* Throws: GraphException if invalid vertices.
*/
public void removeEdge(Comparable searchKey1, Comparable searchKey2) throws GraphException;
/**
* Removes a vetex from the graph.<br>
* Preconditions: must be passed a searchKey to delete.<br>
* Postconditions: removes given searchKey.<br>
* Throws: GraphException if given invalid searchkey.
*/
public GraphNode removeVertex(Comparable searchKey) throws GraphException;
/**
* Gets vertex from graph.<br>
* Preconditions: must be passed a valid searchKey.<br>
* Postconditions: returns a graphNode for the given searchKey.<br>
* Throws: GraphException if given an invaid searchKey.
*/
public GraphNode getVertex(Comparable searchKey) throws GraphException;
/**
* Gets vertex from graph.<br>
* Preconditions: must be passed integer index of node in list.<br>
* Postconditions: returns GraphNode at given index.<br>
* Throws: GraphException if given invalid index value.
*/
public GraphNode getVertex(int index) throws GraphException;
/**
* Obtains a depth-first search of the grap from the given starting vertex.<br>
* Preconditions: must be passed a searchKey for the starting point of the search.<br>
* Postconditions: returns ArrayList of vertices along the search path.<br>
* Throws: GraphException if given invalid searchKey
*/
public ArrayList dfs(Comparable searchKey) throws GraphException;
/**
* Obtains a breadth-first search of the graph.<br>
* Preconditions: must be passed searchKey of the starring point of the search.<br>
* Postconditions: returns an ArrayList of the vertices in the search.<br>
* Throws: GraphException if the searchKey is invalid.
*/
public ArrayList bfs(Comparable searchKey) throws GraphException;
/**
* Returns the shortest path between two vertices in the graph.<br>
* Preconditions: must be passed searchKeys of the starting and ending vertices.<br>
* Postconditions: returns an ArrayList of vertices between the starting and ending search Keys.<br>
* Throws: GraphException if enteres searchKeys are invalid.
*/
public ArrayList shortestPath(Comparable searchKey1, Comparable searchKey2) throws GraphException;
}

81
GraphNode.java Normal file
View File

@ -0,0 +1,81 @@
/**
* GraphNode.java, an object that stores information about a graph node for
* Tree Applicatons.<br>
* Extends: KeyedItem.<br>
* Author: Matt Markham
*/
public class GraphNode extends KeyedItem
{
private int xCoord, yCoord;
boolean mark;
GraphNode (Comparable item)
{
super(item);
mark=false;
}
GraphNode (Comparable item, int x, int y)
{
super(item);
xCoord=x;
yCoord=y;
mark=false;
}
/**
* Returns the x-coordinate of the current Graph Node.<br>
* Preconditions: None.<br>
* Postconditions: Returns int value of this nodes x position.<br>
* Throws: None
*/
public int getX()
{
return xCoord;
}
/**
* Returns the y-coordiante of the current Graph Node.<br>
* Preconditions: None.<br>
* Postconditions: Returns int value of this nodes y position.<br>
* Throws: None
*/
public int getY()
{
return yCoord;
}
/**
* Returns true if node is marked, false if it is not.<br>
* Preconditions: None.<br>
* Postconditions: returns true if node is marked, false if it is not.
* Throws: None.
*/
public boolean isMarked()
{
return mark;
}
/**
* Sets value of mark to true or false.<br>
* Preconditions: Must be passed in a boolean.<br>
* Postconditions: Sets mark to passed-in boolean.<br>
* Throws: None.
*/
public void setMarked(boolean setbool)
{
mark=setbool;
}
public boolean equals (GraphNode node)
{
return ((node.getX() == xCoord)&&(node.getY()==yCoord) && (node.getKey().compareTo(this.getKey())==0));
}
}

267
GraphScreen.java Normal file
View File

@ -0,0 +1,267 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.text.DecimalFormat;
/** This class defines a custom JPanel that will draw vertices, edges, and the shortest path of a Graph object. This custom JPanel is used because it is much easier to intercept x and y coordinates in this panel than in the frame and then having to compensate for the other graphical components. */
public class GraphScreen extends JPanel implements MouseListener {
/** defines the radius of the vertices in pixels */
private final int radius = 20;
/** the path of vertices for the currently displayed shortest path */
private ArrayList path;
/** the graph to add vertices/edges to */
private Graph mygraph;
/** the status bar in the parent jframe */
private JLabel information;
/* a flag to check if you are calculating the shortest path */
private boolean shortestpath;
/* a flag used to check if the mouseclick intercepted was the second in the series (add edge, shortest path) */
private boolean issecondvertex;
/* the data stored in the first vertex clicked in the series */
private Comparable firstvertex;
/**
* Default constructor for the GraphScreen panel. <BR>
* Preconditions: A JLabel status bar in the parent JFrame. <BR>
* Postconditions: Initializes all variables. <BR>
*/
public GraphScreen ( JLabel information ) {
super ( true );
this.information = information;
addMouseListener ( this );
mygraph = new Graph();
mygraph.setShortestPathDisplay ( new ArrayList() );
information.setText ( " Click to add vertex" );
issecondvertex = false;
firstvertex = null;
shortestpath = false;
}
/** mousePressed and mouseReleased could be used to move vertices around the graph,
but as per explicitly stated in the program requirements, the GraphNodes have no
setX ( int x ) and setY ( int y ) methods. */
public void mousePressed ( MouseEvent event ) {}
public void mouseReleased ( MouseEvent event ) {}
/** not used, just here to fully implement the MouseListener interface */
public void mouseEntered ( MouseEvent event ) {}
public void mouseExited ( MouseEvent event ) {}
/**
* Intercepts a mouse click in the drawing window. <BR>
* Preconditions: A mouse click. <BR>
* Postconditions: This method could add a vertex, add an edge, or calculate where the shortest path needs to be based upon flags and user interaction. <BR>
*/
public void mouseClicked ( MouseEvent event ) {
/* If it is a right mouse click, then we must add an edge */
if ( SwingUtilities.isRightMouseButton ( event ) ) {
/* the node that is contained within radius pixels of the MouseEvent */
GraphNode temp = findVertex ( event.getX(), event.getY() );
/* if temp is null then the user clicked in blank space */
if ( temp != null ) {
/* if this is the second right mouse click, and it is not the same vertex */
if ( issecondvertex && firstvertex.compareTo ( temp.getKey() ) != 0 ) {
/* lets add an edge, and hopefully it will work */
try {
addEdge ( firstvertex, temp.getKey() );
information.setText ( " Edge added between " + firstvertex.toString() + " and " + temp.getKey().toString() );
}
/* error exists between keyboard and chair */
catch ( GraphException exception ) {
information.setText ( " Could not add the edge" );
JOptionPane.showMessageDialog ( null, exception.toString(), "Exception caught", JOptionPane.WARNING_MESSAGE );
}
/* we will set all the flags to normal */
issecondvertex = false;
firstvertex = null;
}
/* this must be the first right click intercepted */
else {
/* save the data for use later */
firstvertex = temp.getKey();
issecondvertex = true;
information.setText ( " Right click on another vertex to create an edge" );
}
}
/* we don't care and set everything to normal since the user clicked in blank space */
else {
firstvertex = null;
issecondvertex = false;
information.setText ( " Right click on vertices to add and edge" );
}
}
/* not the right mouse button, so this could be shortest path or add a vertex */
/* if the shortest path flag is set, we must find two different vertices */
else if ( shortestpath ) {
/* if there are less than 2 vertices in the graph, it is impossible to find the shortest path */
if ( mygraph.numVertices() > 2 ) {
GraphNode temp = findVertex ( event.getX(), event.getY() );
/* if this is the second click and the user clicked on a node and the node is not the same node */
if ( issecondvertex && temp != null && firstvertex.compareTo ( temp.getKey() ) != 0 ) {
/* set the shortest path arraylist to the path in the graph */
try {
mygraph.setShortestPathDisplay ( mygraph.shortestPath ( firstvertex, temp.getKey() ) );
information.setText ( " Shortest path is displayed in green" );
repaint();
}
catch ( GraphException exception ) {
JOptionPane.showMessageDialog ( null, exception.toString(), "Exception caught", JOptionPane.WARNING_MESSAGE );
mygraph.setShortestPathDisplay ( new ArrayList() );
information.setText ( " Could not create the shortest path" );
}
shortestpath = false;
issecondvertex = false;
firstvertex = null;
}
/* the user is clicking on blank space */
else if ( temp == null ) {
information.setText ( " You must first click on vertices" );
shortestpath = false;
issecondvertex = false;
firstvertex = null;
}
/* must be the first click in the series then */
else {
firstvertex = temp.getKey();
issecondvertex = true;
information.setText ( " Click on the ending vertex of the path" );
}
}
/* not enough vertices to make a shortest path */
else {
information.setText ( " There must be at least 2 vertices in the graph before calculating the shortest path" );
shortestpath = false;
firstvertex = null;
issecondvertex = false;
}
}
/* well, the only thing left is to add a new vertex */
else {
/* if the user clicked in blank space for once */
if ( findVertex ( event.getX(), event.getY() ) == null ) {
information.setText ( " Click to add vertex" );
shortestpath = false;
issecondvertex = false;
firstvertex = null;
/* ask the user what they want to call it */
String name = JOptionPane.showInputDialog ( null, "Enter name: ","Add new graph node", JOptionPane.QUESTION_MESSAGE );
/* as long as the name appears somewhat valid anyways */
if ( name != null && !name.equals ( "" ) ) {
int x = event.getX(), y = event.getY();
/* these if's check to make sure the user didn't click too close to the edge */
if ( x + radius > getWidth() )
x = getWidth() - radius;
if ( x - radius < 0 )
x = radius;
if ( y - radius > getHeight() )
y = getHeight() - radius;
if ( y - radius < 0 )
y = radius;
try {
mygraph.addVertex ( new GraphNode ( name, x, y ) );
information.setText ( " Vertex added at (" + x + ", " + y + ")" );
repaint();
}
catch ( Exception exception ) {
JOptionPane.showMessageDialog ( null, exception.toString(), "Exception caught!", JOptionPane.WARNING_MESSAGE );
information.setText ( " Vertex could not be added" );
}
}
}
/* the user clicked on a vertex */
else {
information.setText ( " Vertex already added at location" );
JOptionPane.showMessageDialog ( null, "Vertex is already at that point!", "Waitaminit!", JOptionPane.WARNING_MESSAGE );
}
}
}
/**
* Empties the graph and sets all flags to default values. <BR>
* Preconditions: None. <BR>
* Postconditions: Resets all internally used variables to default values. <BR>
*/
public void clearGraph() {
mygraph.makeEmpty();
information.setText ( " Click to add vertex" );
mygraph.setShortestPathDisplay ( new ArrayList() );
issecondvertex = false;
firstvertex = null;
shortestpath = false;
repaint();
}
/**
* Used to set the flag to find the shortest path. <BR>
* Preconditions: None. <BR>
* Postconditions: Sets the shortestpath flag to true. <BR>
*/
public void findShortestPath() {
shortestpath = true;
information.setText ( " Click on the starting vertex" );
}
/**
* Attempts to locate a GraphNode within x +/- radius pixels and y +/- radius pixels of the given coordinate. <BR>
* Preconditions: Two integers representing coordinates inside the GraphScreen. <BR>
* Postconditions: Returns null if no GraphNode is close to the coord. or the GraphNode closest to that point. <BR>
*/
private GraphNode findVertex ( int x, int y ) {
/* look through all of the nodes one by one */
for ( int i = 0; i < mygraph.numVertices(); i++ ) {
GraphNode result = mygraph.getVertex ( i );
int tempx = result.getX();
int tempy = result.getY();
if ( tempx + radius >= x && tempx - radius <= x && tempy - radius <= y && tempy + radius >= y )
return result;
}
return null;
}
/**
* Adds an edge between two vertices. <BR>
* Preconditions: Two comparable objects that are in the graph. <BR>
* Postconditions: Adds an edge between the two vertices containing the comparable objects. <BR>
*/
public void addEdge ( Comparable first, Comparable second ) {
String temp = JOptionPane.showInputDialog ( null, "Enter a weight", "Add an edge", JOptionPane.QUESTION_MESSAGE );
double result = -1.0;
if ( temp != null ) {
try {
result = Double.parseDouble ( temp );
if ( result < 0 )
throw new GraphException ( "Invalid weight for edge." );
mygraph.addEdge ( first, second, result );
information.setText ( " New edge added between vertices {" + (String) first + "} and {" + (String) second + "}" );
repaint();
}
catch ( Exception exception ) {
information.setText ( " Edge could not be added" );
JOptionPane.showMessageDialog ( null, exception.toString(), "Exception Caught", JOptionPane.WARNING_MESSAGE );
}
}
}
/**
* Draws the background for the custom JPanel. <BR>
*/
public void paint ( Graphics g ) {
/* draw a black background */
g.setColor ( Color.black );
g.fillRect ( 0, 0, this.getWidth(), this.getHeight() );
mygraph.draw ( g, radius );
}
}

38
KeyedItem.java Normal file
View File

@ -0,0 +1,38 @@
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();
}
} // end KeyedItem
/*
How to use:
public class CD extends KeyedItem
{
//title not present here
String artist;
...
public CD(String title, String artist, double price, int tracks)
{
super(title);
this.artist=artist;
...
}
}
*/

39
Node.java Normal file
View File

@ -0,0 +1,39 @@
public class Node
{
private Object item;
private Node next; //reference to another node
public Node(Object item)
{
this.item = item;
next = null;
} // end constructor
public Node(Object item, Node next)
{
this.item = item;
this.next = next;
} // end constructor
public void setItem(Object item)
{
this.item = item;
} // end setItem
public Object getItem()
{
return item;
} // end getItem
public void setNext(Node next)
{
this.next = next;
} // end setNext
public Node getNext()
{
return next;
} // end getNext
} // end class Node

7
QueueException.java Normal file
View File

@ -0,0 +1,7 @@
public class QueueException extends RuntimeException
{
public QueueException(String s)
{
super(s);
} // end constructor
} // end QueueException

57
QueueInterface.java Normal file
View File

@ -0,0 +1,57 @@
public interface QueueInterface
{
/**
* Determines whether a queue is empty.
* Precondition: None.
* Postcondition: Returns true if the queue is empty;
* otherwise returns false.
*/
public boolean isEmpty();
/**
* Adds an item at the back of a queue.
* Precondition: item is the item to be inserted.
* Postcondition: If the operation was successful, newItem
* is at the back of the queue. Some implementations
* may throw QueueException if item cannot be added to the queue.
*/
public void enqueue(Object item) throws QueueException;
/**
* Retrieves and removes the front of a queue.
* Precondition: None.
* Postcondition: If the queue is not empty, the item
* that was added to the queue earliest is returned and
* the item is removed. If the queue is empty, the
* operation is impossible and QueueException is thrown.
*/
public Object dequeue() throws QueueException;
/**
* Removes all items of a queue.
* Precondition: None.
* Postcondition: The queue is empty.
*/
public void dequeueAll();
/**
* Retrieves the item at the front of a queue.
* Precondition: None.
* Postcondition: If the queue is not empty, the item
* that was added to the queue earliest is returned.
* If the queue is empty, the operation is impossible
* and QueueException is thrown.
*/
public Object peek() throws QueueException;
/**
* Determines the length of a queue.
* Precondition: None.
* Postcondition: Returns the number of items that are
* currently in the queue.
* Throws: None.
*/
public int size();
} // end QueueInterface

92
QueueReferenceBased.java Normal file
View File

@ -0,0 +1,92 @@
public class QueueReferenceBased implements QueueInterface
{
// circular references
private Node tail;
private int size;
public QueueReferenceBased()
{
tail = null;
size=0;
} // end default constructor
// queue operations:
public boolean isEmpty()
{
return tail == null;
} // end isEmpty
public int size()
{
return size;
}
public void dequeueAll()
{
if (tail!=null)
tail.setNext(null);
tail = null;
size=0;
} // end dequeueAll
public void enqueue(Object item)
{
Node myNode = new Node(item);
// insert the new node
if (isEmpty())
{
// insertion into empty queue
myNode.setNext(myNode);
}
else
{
// insertion into nonempty queue
myNode.setNext(tail.getNext());
tail.setNext(myNode);
} // end if
tail = myNode; // new node is at back
size++;
} // end enqueue
public Object dequeue() throws QueueException
{
if (!isEmpty())
{
// queue is not empty; remove front
Node head = tail.getNext();
if (head == tail)
{ // special case?
tail.setNext(null);
tail = null; // yes, one node in queue
}
else
{
tail.setNext(head.getNext());
} // end if
size--;
return head.getItem();
}
else
{
throw new QueueException("Queue empty");
} // end if
} // end dequeue
public Object peek() throws QueueException
{
if (!isEmpty())
{
// queue is not empty; retrieve front
Node head = tail.getNext();
return head.getItem();
}
else
{
throw new QueueException("Queue empty");
} // end if
} // end peek
} // end QueueCircular

BIN
Quit.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
ShortestPath.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB