import java.util.*; public class myListGraphHide { protected String[] names; // 1-d array to store the vertices protected StringLinkList[] Edges; // 1-d array to store adjacencies between vertices, protected int numVertices; protected int numEdges; // Default constructor. Sets aside enough capacity for one vertex public myListGraphHide( ) { this(1); } // Constructor that sets aside as much capacity as specified by the user public myListGraphHide(int capacity) { names = new String[capacity]; Edges = new StringLinkList[capacity]; for (int i = 0 ; i < capacity ; i ++) { Edges[i] = new StringLinkList(); } } public int numberOfVertices() { return numVertices; } public int numberOfEdges() { return numEdges; } // Finds the location at which a vertex is stored in Vertices. // Returns -1 if vertex not found public int getIndex(String vertex) { for(int i = 0; i < numVertices; i++) if(vertex.equals(names[i])) return i; return -1; } // Resizes the array of vertices. Can make it larger or smaller, depending // on what newSize is. protected String[] resize(String[] array, int newSize) { String[] temp = new String[newSize]; int smallerSize = newSize; if(array.length < smallerSize) smallerSize = array.length; for(int i = 0; i < smallerSize; i++) temp[i] = array[i]; return temp; } // Resizes the array of Edges. Can make it larger or smaller, depending // on what newSize is. protected StringLinkList[] resize (StringLinkList[] array, int newSize) { StringLinkList[] temp = new StringLinkList[newSize]; int smallerSize = newSize; if(array.length < smallerSize) smallerSize = array.length; for(int i = 0; i < smallerSize; i++) temp[i] = array[i]; for (int i = smallerSize ; i < temp.length ; i ++) temp [i] = new StringLinkList(); return temp; } // Adds a new vertex public void addVertex(String newVertex) { if(getIndex(newVertex) != -1) { System.out.print("addVertex: "); System.out.print(newVertex); System.out.println(" failed -- vertex already exists."); return; } // if array of vertices is full, we need to expand it and // also expand Edges if (names.length == numVertices) { names = resize(names, 2*numVertices+1); Edges = resize(Edges, 2*numVertices+1); } names[numVertices++] = newVertex; } // Adds a new edge public void addEdge(String vertex1, String vertex2) { int i = getIndex(vertex1); if(i == -1) { System.out.print("addEdge failed: "); System.out.print(vertex1); System.out.println(" does not exist."); return; } int j = getIndex(vertex2); if(j == -1) { System.out.print("addEdge failed: "); System.out.print(vertex2); System.out.println(" does not exist."); return; } Edges[i].insertFirst(names[j]); Edges[j].insertFirst(names[i]); numEdges++; } // Prints the neighbors of the given vertex public void printAdjacencyList (String vertex) { int i = getIndex(vertex); if(i == -1) { System.out.print("addEdge failed: "); System.out.print(vertex); System.out.println(" does not exist."); return; } System.out.print (vertex + " is connected to "); Edges [i].displayList(); } // returns the names of all the neighbors of a given vertex in a // String array public String[] getNeighbors(String vertex) { int source = getIndex(vertex); if(source == -1) { System.out.print("getNeighbors failed: Vertex "); System.out.print(vertex); System.out.println(" does not exist."); return null; } return Edges[source].copyIntoArray(); } // returns the indices of all the neighbors of a given vertex. The // vertex is specified as an index and the neighbors are returned // in an int array public int[] getNeighbors(int index) { if((index < 0) || (index >= numVertices)) { System.out.print("getNeighbors failed: Index"); System.out.print(index); System.out.println(" is out of bounds."); return null; } // Call the earlier getNeighbors function to get the names of // neighbors String[] nbrNames = getNeighbors(names[index]); // Turn the array of neighbor names into an array // of neighbor indices int[] nbrIndices = new int[nbrNames.length]; for(int i = 0; i < nbrIndices.length; i++) nbrIndices[i] = getIndex(nbrNames[i]); return nbrIndices; } // returns the degree of a vertex with given name public int degree(String vertex) { // Get the index of the vertex int i = getIndex(vertex); if(i == -1) { System.out.print("In degree: "); System.out.print(vertex); System.out.println(" does not exist."); return -1; } // Call the other degree function that returns the degree // of a vertex, given its index return degree(i); } // returns the degree of a vertex with given index public int degree(int index) { return Edges[index].size(); } // Boolean method that tells us if {v1, v2} is an edge in the graph public boolean isEdge(String vertex1, String vertex2) { int i = getIndex(vertex1); if(i == -1) { System.out.print("isEdge failed: "); System.out.print(vertex1); System.out.println(" does not exist."); return false; } int j = getIndex(vertex2); if(j == -1) { System.out.print("isEdge failed: "); System.out.print(vertex2); System.out.println(" does not exist."); return false; } // if vertex2 exists in the adjacency list of // vertex1, then return true return (Edges[i].find(vertex2) != null); } // Computes the clustering coefficient of a vertex. This is the // version that takes a vertex index as argument. public double clusteringCoefficient(int i) { // Copy the adjacency list into an array, for easy access // copyIntoArray is a new method in the GenericLinkList class String[] temp = Edges[i].copyIntoArray(); // initialize edges-in-neighborhood to 0 int edgesInNbd = 0; // Scan pairs of neighbors and increment counter whenever // there is an edge for(int j = 0; j < temp.length; j++) for(int k = 0; k < j; k++) if(isEdge(temp[j], temp[k])) edgesInNbd++; // if there are no neighbors or one neighbor then, clustering // coefficient is trivially defined to be 1. Otherwise, // compute the ratio of number of edges in neighborhood to // the total number of pairs of neighbors if(temp.length <= 1) return 1; else return edgesInNbd*2.0/(temp.length*(temp.length-1)); } // Computes the clustering coefficient of a vertex. This is the // version that takes a vertex name as argument. public double clusteringCoefficient(String v) { int i = getIndex(v); if(i == -1) { System.out.print("clusteringCoefficient failed: "); System.out.print(v); System.out.println(" does not exist."); return 0; } return clusteringCoefficient(i); } // Computes the clustering coefficient of the entire graph // added on 2/23 public double clusteringCoefficient() { double sum = 0; for(int i = 0; i < numVertices; i++) sum = sum + clusteringCoefficient(i); return sum/numVertices; } // Checks whether the graph is connected or not by calling breadthFirstSearch public boolean isConnected() { // Perform breadth first search int[] bfsTree = breadthFirstSearch(names[0]); // Scan the bfsTree array, looking for -1. The graph // is not connected if there is -1 in this array for(int i = 0; i < bfsTree.length; i++) if(bfsTree[i] == -1) return false; return true; } // Returns a 2-d array of vertex names representing the connected components // of the graph. Each row in the 2-d array is a connected component. public String[][] connectedComponents() { // The maximum number of connected components equals the number // of vertices; so start by allocating this many rows. String[][] cc = new String[numVertices][]; // Keeps track of which vertices have been visited by repeated // calls to bfs boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; // Keeps track of the number of vertices have been visited by repeated // calls to bfs int numVisited = 0; // Keeps track of the number of connected components int numComponents = 0; // Repeat bfs until all vertices have been visited while(numVisited < numVertices) { // Scan visited until an unvisited vertex is found // and start bfs at that source int source; for(source = 0; source < numVisited; source++) if(!visited[source]) break; // Compute the bfsTree starting at this source int[] bfsTree = breadthFirstSearch(names[source]); // Scan bfsTree to count number of newly visited vertices int countNewVisited = 0; for(int i = 0; i < numVertices; i++) if(bfsTree[i] != -1) countNewVisited++; // Allocate a row of size countNewVisited in the current row of // cc to store the new connected component cc[numComponents] = new String[countNewVisited]; // Scan bfsTree again, this time to copy the newly visited // vertices into cc and set them as visited countNewVisited = 0; for(int i = 0; i < numVertices; i++) if(bfsTree[i] != -1) { cc[numComponents][countNewVisited++] = names[i]; visited[i] = true; } // Update numVisited numVisited = numVisited + countNewVisited; // Update numComponents numComponents++; } // end while // Resize cc to have exactly as mamy rows as numComponents String[][] newCC = new String[numComponents][]; for(int i = 0; i < numComponents; i++) newCC[i] = cc[i]; return newCC; } // Breadth first search function; returns a breadth first search tree // stored in an array of integers with the entry in slot i containing // the index of the parent of the vertex with index i public int[] breadthFirstSearch(String source) { int sourceIndex = getIndex(source); if(sourceIndex == -1) { System.out.print("breadthFirstSearch failed: "); System.out.print(source); System.out.println(" does not exist."); return null; } // Initialize the bfsTree array; the entry -1 means // not yet visited. int[] bfsTree = new int[numVertices]; for(int i = 0; i < numVertices; i++) bfsTree[i] = -1; // The parent of the tree root is itself bfsTree[sourceIndex] = sourceIndex; // Then initialize the visited array boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; visited[sourceIndex] = true; // Then initialize the queue Queue Q = new Queue(numVertices); Q.enqueue(sourceIndex); while(!Q.isEmpty()) { // get the index of the vertex first in line int current = Q.dequeue(); // Get the indices of the neighbors of the current vertex int[] neighbors = getNeighbors(current); // Scan the neighbors for(int i = 0; i < neighbors.length; i++) { // Get the index of the current neighbor int currentNeighbor = neighbors[i]; // Check if the neighbor is new, i.e., not visited // If so, mark the neighbor as visited, enqueue the neighbor, and // set the neighbor's parent in bfsTree if(!visited[currentNeighbor]) { visited[currentNeighbor] = true; Q.enqueue(currentNeighbor); bfsTree[currentNeighbor] = current; } } // end-scanning neighbors } // end-while Q is not empty return bfsTree; } void depthFirstSearch(String source) { int sourceIndex = getIndex(source); if(sourceIndex == -1) { System.out.print("depthFirstSearch failed: "); System.out.print(source); System.out.println(" does not exist."); return; } // Initialize the visited array boolean[] visited = new boolean[numVertices]; for(int i = 0; i < numVertices; i++) visited[i] = false; visited[sourceIndex] = true; System.out.println(names[sourceIndex]); // Then initialize the stack myIntStack S = new myIntStack(numVertices); S.push(sourceIndex); while(!S.isEmpty()) { // get the index of the vertex first in line int current = S.pop(); // Get the indices of the neighbors of the current vertex int[] neighbors = getNeighbors(current); // Scan the neighbors for(int i = 0; i < neighbors.length; i++) { // Get the index of the current neighbor int currentNeighbor = neighbors[i]; // Check if the neighbor is new, i.e., not visited // If so, mark the neighbor as visited, enqueue the neighbor, and // set the neighbor's parent in bfsTree if(!visited[currentNeighbor]) { visited[currentNeighbor] = true; System.out.println(names[currentNeighbor]); S.push(current); S.push(currentNeighbor); break; } // end-if } // end for-loop } // end while-loop } // end depth-first search } // end of class