 Hello and welcome to this session in which we look at some simple algorithms on graph. In particular we look at what are called graph traversals. So what is a graph traversal? As we have seen the most basic question on graphs is given two nodes N and N, find a path in the graph that starts from N and ends at N. That is we want to start at node N, move to some successor of N and keep moving to successors of node till we reach the node N. So this is exactly the problem of trying to go from city X to city Y by using an airlines connections that are available. There may not be a direct connection but there may be a path from X to Y which is essentially a sequence of flights that you can take to reach from X to Y. So the representation of a graph gives us only local information about the graph. For every node it tells us which nodes are its successor or given two nodes it tells us whether one is the successor of another. But the properties of graphs that we are interested in are you mainly global properties of the graph. The existence of a path for example is a global property. Just by looking at all the successors of a given node we cannot say whether there is a path from a given node N to N. We need to go through list of all the nodes in the graph to see whether it is possible to reach a node N by a path starting from a node N. And a graph traversal is a systematic way of collecting information about the entire graph and we gather the information by traversing the whole graph in a systematic way. And this information then can then be used to solve many other problems on graph. So we look at one such method which is called depth force search in a graph which is a systematic way of visiting all nodes of a graph. So while traversing the graph we will gather information about it and use this later to solve many other problems. So depth force search turns out to be the first step for many problems on graph and in many algorithms the first step that you perform is depth force search. And this is especially useful for finding paths and cycles in a graph and related problems. So what is depth force search? So we define a function called traverse s comma v. So s is a sequence of nodes in the graph to be visited and v is a sequence of nodes that have been visited. So traverse will finally return as a sequence of all nodes that get visited. But it uses currently two sequences of nodes one which is yet to be visited and v is visit those which have been visited. And the important point is it will return a sequence of nodes in a particular order in the order in which they get visited during our traversal. So this is similar to for example pre-order traversal of a tree which generates a sequence of all nodes of the tree in a particular order. Similarly depth force search and generates a sequence of all nodes in the graph in a particular order. So traverse pi comma v is v. So if no more nodes remain to be visited then we just return the list of nodes that have already been visited and that is the final list of all nodes in the graph. So traverse pi comma v is v. If the sequence of nodes to be visited is not empty. So there exists a node n the first node n to be which we know has not been visited or which may or may not have been visited. We check whether it already occurs in the set of visited nodes. If it does then we do not do anything we just move to the next node in the sequences. So if a node in s is already occurred in v then we ignore this node and do nothing. Otherwise we will do what is called depth force search starting from node n and with the set of visited nodes v and take that as our new set of visited nodes. So the set of visited nodes is expanded starting from this new node n. So we found a node n which was not visited and we start what is called a depth force search from node n with the current set of visited nodes and expand the set of visited nodes to be the set n comma v dfs n comma v and then traverse the remaining sequence of unvisited nodes in s. And dfs essentially to starting from node n all it does is it adds v to the list of visited nodes. So new sequence of visited nodes becomes obtained by concatenating v and the sequence push n comma 5. So we add n to the end of the sequence of visited nodes v and that is our new list of visited nodes. And now we traverse through all the successors of the node n and again look check if any one of the successors has been visited or not. So if you find a successor which has not been visited it will again call depth force search for that successor and again it will push that successor into the list of visited nodes and so on. So this is a compact way of describing depth force search in a graph. Essentially we keep expanding the set of visited nodes. Every time a new node is found which is unvisited we start a depth force search function from that. All that depth force search does is it adds this node to the set of visited nodes and it calls depth force search for the successors of itself. So traverse s comma 5 so when we start with the set of all nodes in the graph and empty set is the initial visited sequence of nodes. This will return all nodes in the graph in the order in which they give visited. On the other hand DFS n comma 5 will return a sequence of nodes to which there is a path in the graph from node n. So if there is no path from node n to some node it will not get added to the sequence DFS n5 and this is something that you can prove by induction. By just looking at the definitions of these functions can show that only if there is a path from node n to node m will node m appear in the sequence DFS n5. So the function that we have defined only test whether there is a path in the graph but we can modify to actually return the sequence of nodes in the graph from node n to node m and we usually need to do many other computations apart from ordering the nodes in the graph while doing depth force search. So alternatively we can write this in a more programming style. So here DFS n comma 5 constructs a tree with root n of nodes that are reachable from n. So instead of returning just a sequence of nodes now DFS n5 is actually returning a rooted tree with n as the node and it will essentially return a tree of all the nodes that are reachable from node n in the graph. And then the path from any node in this tree to n can be found by following the parent array in this tree. So for every node we will find its parent in this tree and that we will finally come back to the root node which will be n and that will give us the path from n to any node in this tree. So initially the tree contains only the node n and no subtree the list of subtrees is empty and we add n to the list of vertices which are visited. So DFS nv just modifies the set of visited vertices and it constructs a tree and returns the tree as a return value. Then all that we need to do is look at all successors of the node n and pick any element i in that list of successors. If m has not been visited if it does not belong to the sequence v then we attach the or we call DFS m with the new list of visited vertices that returns a tree and attach t itself to attach to the tree t the new tree that has been written. So that is the new subtree that gets attached to the list of subtree of the tree t that we have got initially when we had no subtree to that when a successor is found which has not been visited we will call DFS for that successor it will return some subtree of nodes reachable from that successor and we will attach that as a subtree of the tree t finally we will return the tree t. So this is a more programming style of describing that for such much more compact if you use the functional description but this is more powerful you can do more things like computing the parent and so on using this. There is an alternative way of traversing a graph so just as in tree we had pre-order post-order this is a different way of traversing a graph which is called breadth-first search and this is especially useful when we want to find a path with minimum number of nodes from a given node to another node. So depth-first search will just give you one possible path from node n to node n but it may be a very long path so if you are using it to find a flight from x to y we may end up going through a very roundabout way but then breadth-first search is a better option which gives a shortest possible path from a node n to node n. So this is also defined in a similar way we have a list of nodes to be visited and a list of nodes which have been visited and we defined the traverse function in a similar way if node n has already been visited then we do nothing we just traverse the remaining sequence of node the list of visited nodes remains the same if node n has not been visited then we call breadth-first search from this node and we will add a new set of nodes to the visited set of nodes so the visited sequence now will be defined by BFS and BFS will be obtained by concatenating the node n to the set of visited nodes and we will add n to another sequence which is a Q. So BFS takes two parameters V and Q V is essentially the set of visited nodes Q is a set of nodes which we have visited but whose successors may not have been visited so the property is that V contains all visited nodes Q contains nodes which have been visited but whose successors may not have been visited. So this is what breadth-first search with view if the Q has become empty that is all nodes have been visited and their successors have also been visited then we just return the sequence V of the set of visited nodes otherwise we pick out the front element of the Q and remove it from the Q look at all successors of that element n if some successor does not occur in the sequence V so that is it has not been visited so far then we add this element m to the sequence V insert this element in the Q because now we do not know whether successors of m have been visited or not so we will also insert m in this Q and in this case again we set parent of m equal to n so this will again define a tree called a breadth-first search tree finally we return the sequence VFS VQ after modifying V and Q in this form so this is an alternative way of traversing a graph now we can use the similar ideas for many other problems on graph so we consider what are called directed acyclic graph so a graph with acyclic effect does not contain a cycle so many graphs in different applications are required to be acyclic so for example graph of course prerequisites cannot have a cycle because that would mean that you cannot start on any of those courses every course has a prerequisite which is in the cycle so then there is no course that you can start on that at all so this graph surely cannot have a cycle so property of such graph is what is called a topological ordering so it is an ordering of the nodes of the graph such that every ordered pair nm corresponding to n edge n occurs before m in the ordering so all the edges of the graph go from a node which occurs earlier in the ordering to a node which occurs later in the ordering and such an ordering can be used to solve many problems for directed acyclic graph and we can use depth-first search to find this ordering so here is a simple definition of top sort similar to this so this is exactly similar to the traverse function we will again call dfs if the node has not been visited and add the set of node flood get visited to the set of visited nodes nb the only difference here is in the dfs instead of pushing the node into the set of visited nodes right at the beginning of the call to dfs we do it after looking at all its successor so we will first do depth-first search on all the successor that will end up visiting some other nodes and then the node n itself is added last to the sequence b or it is added at the beginning of the sequence v so instead of adding it at the end of the sequence v as we were doing previously we will add it to the beginning of the sequence so in this case the nodes in v will actually appear in the order in which dfs was completed for that node rather than the order in which the nodes were visited so this gives a different ordering but this will have the property of a topological ordering if the graph is directed acyclic so this will give a valid ordering if the nodes in the graph is acyclic however it does not check whether the given graph is acyclic so after you have got the graph and you have got this ordering you can go through the list of edges and check that every edge goes from a node which occurs earlier to a node which occurs later if it does not then this graph is not acyclic and you can modify this function to actually find the cycle so you can try that as an exercise and this completes our session on graph we will see more about graphs when we consider implementations and algorithms on graphs thank you