220 likes | 444 Views
Graphs – Part II. CS 367 – Introduction to Data Structures. Implementing a Graph. Nodes must store data Graph must have an adjacency list (or matrix) we will use an adjacency matrix for best performance, should have access to all nodes in the graph
E N D
Graphs – Part II CS 367 – Introduction to Data Structures
Implementing a Graph • Nodes • must store data • Graph • must have an adjacency list (or matrix) • we will use an adjacency matrix • for best performance, should have access to all nodes in the graph • we will keep an array of references to each node • there are other ways to do this • Many ways to implement a graph – we will look at just one possible implementation
Cycles • A cycle is defined as a route from: N0 to N1 to … Nm-1 to Nm where N0 equals Nm • In other words, you follow some path of edges that leads you back to the node you started at A E Cycle A -> B -> D -> A B C D F
Cycles • If cycles are not considered, it is easy to end up with code that results in an infinite loop • to prevent this, mark each visited node with a special flag • before starting a search, mark the node as false • after visiting a node, mark it as true • do not go to nodes that are already marked as visited
Graph Methods • Many possible methods to put in a graph class • insert, remove, search, etc. • For now, we will only consider searching a graph for data • assume we have a method to build the graph based on a data file • we’ll show how to do this later
Graph Searching • Unlike a tree, a graph is not required to have a specific ordering of data • in fact, in many graphs this would be impossible • must traverse the entire graph to find the data • Two possible graph traversal methods • depth first search • breadth first search • To simplify things, we will assume that the search methods do the following • accept an object that indicates where the search should start • goes through every node in the graph and prints out
Graph Node Class class GraphNode { public Object data; public boolean visited; public int index; public GraphNode(Object data) { this.data = data; visited = false; } } • There may be much more data than this stored in a node • this will be fine for our examples
Graph Class class Graph { private GraphNode[ ] nodes; private int[ ][ ] matrix; public Graph(int numNodes, String dataFile) { nodes = new GraphNode[numNodes]; matrix = new int[numNodes][numNodes]; createGraph(nodes, matrix, dataFile); } private void createGraph(GraphNode[ ] nodes, int[ ][ ] matrix, String data); public void depthFirst(Object start) { for(int i=0; i<nodes.lenth; i++) { nodes[i].visited = false; } for(int i=0; i<nodes.length; i++) if(nodes[i].data.equals(start)) { depthFirst(i); return; } System.out.println(“Starting point not in graph.”); } private void depthFirst(int start); public void breadthFirst(Object start) { … } private void breadthFirst(int start); }
Depth First Search • The idea of depth in a graph is how far from the source node can you go • visit a node, N • visit the first neighbor, N1, of N • visit N1’s first neighbor, N11, and so on • be careful not to visit an already visited node • once the first adjacent node has been visited (and each of its adjacent nodes), move to the next node • repeat this until all the nodes are visited
Depth First Search • Implementation • two possible implementations • recursion • stack • both methods are similar • push a node on the stack (user or program stack) • visit the node • look at the nodes adjacency list (or matrix) • select the first unvisited adjacent node • visit that node and repeat the process
Depth First Search - Recursion // notice that no error checking is being performed – there should be! public void depthFirst(int start) { GraphNode cur = nodes[start]; cur.visited = true; System.out.println(cur.data); for(int i=0; i<nodes.length; i++) { if((matrix[start][i] == 1) && (nodes[i].visited == false)) depthFirst(i); } } • Again, in reality more than simply printing a nodes value would occur on a visit to the node
Depth First Search - Recursion E Program Stack F F B B B A A A A A E B C F D B B B B D F A A A A depthFirst(A) C A A A
Depth First Search • It should be clear from the previous example that using recursion to do a depth first search involves using a stack • the program stack in this case • implicitly handled by the compiler • You should also be able to convert this into a program that uses and explicit stack • similar to your flight path program that first used recursion and then a stack
Breadth First Search • The idea of breadth in a graph deals with visiting all of a nodes neighbors before moving on • visit a node, N • visit all of N’s neighbors • then go to N’s first neighbor, N1, and visit all of N1’s neighbors • then to to N’s next neighbor, N2, and visit all of N2’s neighbors • repeat this until all the nodes are visited
Breadth First Search • Implementation • use a queue to store each visited node’s neighbors • start by enqueueing the root • dequeue the first node from the queue • visit the node • enqueue all of the nodes neighbors • be careful not to enqueue an already visited node • dequeue the next node from the queue and repeat the process
Breadth First Search // notice that no error checking is being performed – there should be! public void breadthFirst(int start) { QueueList queue = new QueueList(); queue.enqueue(nodes[start]); while(!queue.isEmpty()) { GraphNode tmp = (GraphNode)queue.dequeue(); System.out.println(tmp.data); for(int i=0; i<nodes.length; i++) { if((matrix[tmp.index][i] == 1) && (nodes[i].visited == false)) queue.enqueue(nodes[i]); } } }
Breadth First Search A E visit A A visit E B C E visit B B C C D F D visit C F visit F D F breadthFirst(A) visit D F
Creating the Graph • The constructor for a graph contained createGraph(nodes, matrix, dataFile); • How is the graph originally constructed? • it depends on the format of the initial data • in this case, we assume a file contains all the information • it could be gotten through user input • the graph could be built as needed • consider a chess game again – build the nodes as needed
Creating a Graph from a File • Assume a data file where the first column represents a node • every other column on a line represent immediate neighbors to the first node Data File A A B C B D F C D D A F E E B C D F
Creating a Graph from a File • Basic concept • initialize the matrix array to all zeroes • read a line from the file • create a new GraphNode for each column that has not yet been created • insert it into the nodes array • go to the row in the matrix indicated by the first column • go through the row and place a one for every neighbor listed in the file
Creating a Graph from a File private void createGraph(GraphNode[ ] nodes, int[ ][ ] matrix, String file) { // open the file for reading // initialize matrix array to all zeroes // read the first line from the file while(line != null) { StringTokenizer tok = new StringTokenizer(line); // if the first token isn’t in the nodes array, add it // set row equal to the location of the first token in the nodes array while(tok.hasMoreTokens()) { String tmp = tok.next(); // if tmp isn’t in nodes array, add it and place a 1 in matrix // otherwise, just place a 1 in matrix } // read the next line from the file } }
Creating a graph from a File • One caution when creating the graph • need to make sure that nodes array indices are aligned with matrix indices • in other words, if node B is found at index 1 of the nodes array, it should also be represented by row 1 and column 1 in the matrix array