lab04
This commit is contained in:
2 files changed
+424
No files matched your search
@@ -0,0 +1,395 @@
|
|||||||
|
package ca.bcit.comp3760.lab04;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
public class Graph
|
||||||
|
{
|
||||||
|
private static final int NO_EDGE = 0;
|
||||||
|
private static final int EDGE = 1;
|
||||||
|
|
||||||
|
private final String[] vertices;
|
||||||
|
private final int[][] edges;
|
||||||
|
private final boolean directed;
|
||||||
|
|
||||||
|
private String lastDFSOrder;
|
||||||
|
private String lastDFSDeadEndOrder;
|
||||||
|
private String lastBFSOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a graph with the given vertex labels and direction setting.
|
||||||
|
*
|
||||||
|
* @param vertexLabels array of vertex names in internal order
|
||||||
|
* @param isDirected true if the graph is directed, false otherwise
|
||||||
|
*/
|
||||||
|
public Graph(final String[] vertexLabels, final boolean isDirected)
|
||||||
|
{
|
||||||
|
final int n;
|
||||||
|
|
||||||
|
n = vertexLabels.length;
|
||||||
|
|
||||||
|
this.vertices = vertexLabels;
|
||||||
|
this.edges = new int[n][n];
|
||||||
|
this.directed = isDirected;
|
||||||
|
|
||||||
|
this.lastDFSOrder = null;
|
||||||
|
this.lastDFSDeadEndOrder = null;
|
||||||
|
this.lastBFSOrder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this graph is directed.
|
||||||
|
*
|
||||||
|
* @return true if directed, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isDirected()
|
||||||
|
{
|
||||||
|
return this.directed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an edge from one vertex to another.
|
||||||
|
* If the graph is undirected, the reverse edge is also added.
|
||||||
|
* If either vertex label does not exist, nothing happens.
|
||||||
|
*
|
||||||
|
* @param va starting vertex label
|
||||||
|
* @param vb ending vertex label
|
||||||
|
*/
|
||||||
|
public void addEdge(final String va, final String vb)
|
||||||
|
{
|
||||||
|
final int fromIndex;
|
||||||
|
final int toIndex;
|
||||||
|
|
||||||
|
fromIndex = findVertexIndex(va);
|
||||||
|
toIndex = findVertexIndex(vb);
|
||||||
|
|
||||||
|
if (fromIndex == -1 || toIndex == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.edges[fromIndex][toIndex] = EDGE;
|
||||||
|
|
||||||
|
if (!this.directed)
|
||||||
|
{
|
||||||
|
this.edges[toIndex][fromIndex] = EDGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of vertices in the graph.
|
||||||
|
*
|
||||||
|
* @return number of vertices
|
||||||
|
*/
|
||||||
|
public int size()
|
||||||
|
{
|
||||||
|
return this.vertices.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the label of the vertex at the given internal index.
|
||||||
|
*
|
||||||
|
* @param v internal vertex index
|
||||||
|
* @return label of the vertex
|
||||||
|
*/
|
||||||
|
public String getLabel(final int v)
|
||||||
|
{
|
||||||
|
return this.vertices[v];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the graph adjacency matrix.
|
||||||
|
*
|
||||||
|
* @return adjacency matrix as a string
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
final StringBuilder graph;
|
||||||
|
|
||||||
|
graph = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < this.vertices.length; ++i)
|
||||||
|
{
|
||||||
|
graph.append(this.vertices[i]);
|
||||||
|
graph.append(": ");
|
||||||
|
|
||||||
|
for (int j = 0; j < this.vertices.length; ++j)
|
||||||
|
{
|
||||||
|
graph.append(this.edges[i][j]);
|
||||||
|
|
||||||
|
if (j < this.vertices.length - 1)
|
||||||
|
{
|
||||||
|
graph.append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < this.vertices.length - 1)
|
||||||
|
{
|
||||||
|
graph.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return graph.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findVertexIndex(final String label)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < this.vertices.length; ++i)
|
||||||
|
{
|
||||||
|
if (this.vertices[i].equals(label))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendVertex(final StringBuilder order, final String label)
|
||||||
|
{
|
||||||
|
if (order.length() > 0)
|
||||||
|
{
|
||||||
|
order.append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
order.append(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DFS(final int idx,
|
||||||
|
final boolean[] visited,
|
||||||
|
final boolean quiet,
|
||||||
|
final StringBuilder visitOrder,
|
||||||
|
final StringBuilder deadEndOrder)
|
||||||
|
{
|
||||||
|
visited[idx] = true;
|
||||||
|
appendVertex(visitOrder, this.vertices[idx]);
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.out.printf("Visiting vertex %s%n", this.vertices[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this.edges[idx].length; ++i)
|
||||||
|
{
|
||||||
|
if (this.edges[idx][i] == EDGE && !visited[i])
|
||||||
|
{
|
||||||
|
DFS(i, visited, quiet, visitOrder, deadEndOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendVertex(deadEndOrder, this.vertices[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs depth first search using the default first-on-the-list rule.
|
||||||
|
* If the graph is disconnected, all vertices are still included.
|
||||||
|
*
|
||||||
|
* @param quiet true to suppress console output, false to print traversal
|
||||||
|
*/
|
||||||
|
public void runDFS(final boolean quiet)
|
||||||
|
{
|
||||||
|
final boolean[] visited;
|
||||||
|
final StringBuilder visitOrder;
|
||||||
|
final StringBuilder deadEndOrder;
|
||||||
|
|
||||||
|
visited = new boolean[this.vertices.length];
|
||||||
|
visitOrder = new StringBuilder();
|
||||||
|
deadEndOrder = new StringBuilder();
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.out.println("DFS order traversal of graph:");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this.vertices.length; ++i)
|
||||||
|
{
|
||||||
|
if (!visited[i])
|
||||||
|
{
|
||||||
|
DFS(i, visited, quiet, visitOrder, deadEndOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastDFSOrder = visitOrder.toString();
|
||||||
|
this.lastDFSDeadEndOrder = deadEndOrder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs depth first search starting at the given vertex.
|
||||||
|
* Only vertices reachable from the start vertex are included.
|
||||||
|
*
|
||||||
|
* @param v starting vertex label
|
||||||
|
* @param quiet true to suppress console output, false to print traversal
|
||||||
|
*/
|
||||||
|
public void runDFS(final String v, final boolean quiet)
|
||||||
|
{
|
||||||
|
final int startIndex;
|
||||||
|
final boolean[] visited;
|
||||||
|
final StringBuilder visitOrder;
|
||||||
|
final StringBuilder deadEndOrder;
|
||||||
|
|
||||||
|
startIndex = findVertexIndex(v);
|
||||||
|
|
||||||
|
if (startIndex == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
visited = new boolean[this.vertices.length];
|
||||||
|
visitOrder = new StringBuilder();
|
||||||
|
deadEndOrder = new StringBuilder();
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.out.println("DFS order traversal of graph:");
|
||||||
|
}
|
||||||
|
|
||||||
|
DFS(startIndex, visited, quiet, visitOrder, deadEndOrder);
|
||||||
|
|
||||||
|
this.lastDFSOrder = visitOrder.toString();
|
||||||
|
this.lastDFSDeadEndOrder = deadEndOrder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BFS(final int startIndex,
|
||||||
|
final boolean[] visited,
|
||||||
|
final boolean quiet,
|
||||||
|
final StringBuilder bfsOrder)
|
||||||
|
{
|
||||||
|
final Queue<Integer> queue;
|
||||||
|
|
||||||
|
queue = new LinkedList<>();
|
||||||
|
|
||||||
|
visited[startIndex] = true;
|
||||||
|
queue.offer(startIndex);
|
||||||
|
|
||||||
|
while (!queue.isEmpty())
|
||||||
|
{
|
||||||
|
final int current;
|
||||||
|
|
||||||
|
current = queue.poll();
|
||||||
|
appendVertex(bfsOrder, this.vertices[current]);
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.out.printf("Visiting vertex %s%n", this.vertices[current]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int next = 0; next < this.edges[current].length; ++next)
|
||||||
|
{
|
||||||
|
if (this.edges[current][next] == EDGE && !visited[next])
|
||||||
|
{
|
||||||
|
visited[next] = true;
|
||||||
|
queue.offer(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs breadth first search using the default first-on-the-list rule.
|
||||||
|
* If the graph is disconnected, all vertices are still included.
|
||||||
|
*
|
||||||
|
* @param quiet true to suppress console output, false to print traversal
|
||||||
|
*/
|
||||||
|
public void runBFS(final boolean quiet)
|
||||||
|
{
|
||||||
|
final boolean[] visited;
|
||||||
|
final StringBuilder bfsOrder;
|
||||||
|
|
||||||
|
visited = new boolean[this.vertices.length];
|
||||||
|
bfsOrder = new StringBuilder();
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.out.println("BFS order traversal of graph:");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this.vertices.length; ++i)
|
||||||
|
{
|
||||||
|
if (!visited[i])
|
||||||
|
{
|
||||||
|
BFS(i, visited, quiet, bfsOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastBFSOrder = bfsOrder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs breadth first search starting at the given vertex.
|
||||||
|
* Only vertices reachable from the start vertex are included.
|
||||||
|
*
|
||||||
|
* @param v starting vertex label
|
||||||
|
* @param quiet true to suppress console output, false to print traversal
|
||||||
|
*/
|
||||||
|
public void runBFS(final String v, final boolean quiet)
|
||||||
|
{
|
||||||
|
final int startIndex;
|
||||||
|
final boolean[] visited;
|
||||||
|
final StringBuilder bfsOrder;
|
||||||
|
|
||||||
|
startIndex = findVertexIndex(v);
|
||||||
|
|
||||||
|
if (startIndex == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
visited = new boolean[this.vertices.length];
|
||||||
|
bfsOrder = new StringBuilder();
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.out.println("BFS order traversal of graph:");
|
||||||
|
}
|
||||||
|
|
||||||
|
BFS(startIndex, visited, quiet, bfsOrder);
|
||||||
|
|
||||||
|
this.lastBFSOrder = bfsOrder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the DFS visit order from the most recently run DFS.
|
||||||
|
*
|
||||||
|
* @return DFS order string, or a message if DFS has not been run
|
||||||
|
*/
|
||||||
|
public String getLastDFSOrder()
|
||||||
|
{
|
||||||
|
if (this.lastDFSOrder == null)
|
||||||
|
{
|
||||||
|
return "No DFS has been run yet.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.lastDFSOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the DFS dead-end order from the most recently run DFS.
|
||||||
|
*
|
||||||
|
* @return DFS dead-end order string, or a message if DFS has not been run
|
||||||
|
*/
|
||||||
|
public String getLastDFSDeadEndOrder()
|
||||||
|
{
|
||||||
|
if (this.lastDFSDeadEndOrder == null)
|
||||||
|
{
|
||||||
|
return "No DFS has been run yet.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.lastDFSDeadEndOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the BFS visit order from the most recently run BFS.
|
||||||
|
*
|
||||||
|
* @return BFS order string, or a message if BFS has not been run
|
||||||
|
*/
|
||||||
|
public String getLastBFSOrder()
|
||||||
|
{
|
||||||
|
if (this.lastBFSOrder == null)
|
||||||
|
{
|
||||||
|
return "No BFS has been run yet.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.lastBFSOrder;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package ca.bcit.comp3760.lab04;
|
||||||
|
|
||||||
|
public class GraphDriver
|
||||||
|
{
|
||||||
|
public static void main(final String[] args)
|
||||||
|
{
|
||||||
|
final Graph G;
|
||||||
|
G = new Graph(new String[]{"a", "b", "c", "d", "e", "f", "g", "h"}, false);
|
||||||
|
|
||||||
|
G.addEdge("a", "b");
|
||||||
|
G.addEdge("a", "e");
|
||||||
|
G.addEdge("a", "f");
|
||||||
|
G.addEdge("b", "f");
|
||||||
|
G.addEdge("b", "g");
|
||||||
|
G.addEdge("c", "d");
|
||||||
|
G.addEdge("c", "g");
|
||||||
|
G.addEdge("d", "h");
|
||||||
|
G.addEdge("e", "f");
|
||||||
|
G.addEdge("g", "h");
|
||||||
|
|
||||||
|
System.out.printf("%s\n\n", G.toString());
|
||||||
|
|
||||||
|
G.runDFS(false);
|
||||||
|
|
||||||
|
System.out.println("\n");
|
||||||
|
|
||||||
|
G.runBFS(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user