Initial revision

master
mercury 2003-12-04 02:28:46 +00:00
commit 5dcbf60660
5 changed files with 778 additions and 0 deletions

511
Graph.java Normal file
View File

@ -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;
}
}

193
GraphDriver.java Normal file
View File

@ -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();
}
}
}

9
GraphException.java Normal file
View File

@ -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);
}
}

44
GraphNode.java Normal file
View File

@ -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);
}
}

21
KeyedItem.java Normal file
View File

@ -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();
}
}