 Hello and welcome to this next lecture on data structures and algorithms. We will continue our discussion on graph traversal algorithms. We will consider the next one, the depth first search. Contrasting depth first search with breadth first search, the main difference is that a node and the subtree corresponding to that node is completely explored before other siblings of the node are explored. So, like before we will adopt a legend for nodes, different labels that will be assigned to nodes. By default every node is unexplored and in fact every edge is also unexplored. So, that is the initialization. Every node in every edge is labeled as unexplored and then for each connected component in the graph you find a vertex and perform a DFS. So, DFS for a V belonging to each connected component. Now, what does this DFS itself going to do? Like before DFS is going to assign labels, then labels node labels we are looking at now are visit the edge labels like before are discovery. There is a slight difference now. Back edges are labeled red as against cross edges that we encountered in the case of breadth first search. The back edge is basically an edge to an ancestor of the tree as against to a node which is a sibling or a descendant of sibling. Now, these back edges become very handy when it comes to detecting cycles in the graph. So, the DFS. So, DFS iterates over every node in the graph and in fact you begin with all the edges incident on a node. I am going to illustrate this now. So, here we begin with some nodes 1, 2, 3, 4, 5. We begin with V and that is the first node. Look at all the edges incident on that first node. You get a W that is 2. Look at the label of W it is all unexplored. In fact all the nodes in black are non-explored. If so then set the label of E this particular edge to discovery edge and also perform a DFS on the node label 2. What does this DFS in turn do? Well, it is going to look at all the neighbors of 2. There is just one start with the first one. In fact before starting off with that edge you would label 2 itself as discovered. So, node is labeled as discovered before any subsequent DFS activities performed. So, you will do likewise for 4 perform a DFS and you come across 3. You try and perform a DFS but you find that this W 1 at least in the first node that 3 is connected to happens to be already explored. So, that is when you decide to set the label of E to a back. This is a back edge. What it means is that we have come across a cycle. Of course, now there is no more DFS to perform on one. So, you trade over all the other edges of 3 you have one more edge which you can mark as discovery edge, discovered edge and then phi. What happens when you invoke DFS of phi is that you do not have any edges incident on phi. So, now you start going backward to 3, 3 has no other edges, 4 has no other edges, node is 2 have and so on. Now, this is a very simple version of DFS which makes use of a recursive call. So, we are going to make this DFS procedure somewhat smarter. The first thing we will do towards that is eliminate recursive call and we will basically do that by making use of the stack auxiliary data structure. How would you do that? Well, we are going to move the part of DFS simulated by having W inserted into a stack. So, we are going to defer the DFS call here. In fact, shift the DFS call to the main DFS itself. I might just do well by putting across here and for this particular W, I am going to insert a push W into a stack S. We will assume that S was initialized to be empty and you want to do this for all the E edges incident on V. What does this mean? We are saying that if this was V, it had multiple edges and E 1, W 1, E 2, W 2 and so on. We are going to push each of W 1, W 2 and so on into the stack and once we have exhausted all the incident edges for V, which is at this point of time, we are going to say I will pop elements from the stack. So, what we need to do is as follows. We will need to initially insert the element V into the stack, add a while, a while block while S dot not empty. That is while S has some elements to pop, we are going to pop the latest element V. You might want to call the start node V prime and this will be a specific V. So, V is S dot pop, you pop out the element, perform all these activities on the incident edges for V, get all the W's, push all those W's into S and continue this whole exercise till S becomes empty. So, this is going to give you the same effect as the original DFS call without needing to invoke recursion. We can also make some other interesting modifications to this procedure by doing some more bookkeeping. So, recall that for BFS, the bookkeeping we introduced was that of depth and ancestor. So, what we will do is like in BFS, introduce some additional bookkeeping. So, what bookkeeping are we talking about? Well, first of all we can keep track of the vertex that led to an expansion of the current vertex. So, what I mean by the keeping track of for expansion is as follows. So, as I push W into S, I will also set the pi of W, the ancestor of W to be V. Initially of course, the ancestor of V prime is nil, it is a root, but I will set the pi of W to be V. I can also keep track not just of depth, but of the time that a particular node started getting expanded and the time that we stopped expanding a particular node. So, we start expanding a particular node moment we pop that node. We can also do some additional bookkeeping in terms of when a particular node starts getting expanded, when the subtree for that node V gets expanded the beginning of that and the beginning of that basically V of V. We can set it to some time, this time is initially 0 and it increases the moment I start expanding a node time plus plus. However, it is a little tricky to keep track of when the expansion on V concludes because the expansion on V concludes when the expansion of all its descendants is also concluded. So, this expansion becomes very natural when you have the DFS call. So, what I am going to do is state the following E of V is time plus plus if recursion is used and what this means is that the call DFS GW were used instead of the stack. E of V could also be set in the case of the stack being used instead of the recursive call, but I am going to leave that as homework. Your homework will be how would you set E V the end time for expansion of subtree for node V if stack were used instead of recursion. So, some of this bookkeeping might become handy in subsequent discussions. Let us now look at the complexity of DFS. We are going to illustrate DFS through a slightly more interesting example. You have a node D where you begin with and you explore this edge to visit A, explore the next edge from A to visit B. From B you visit C, E and now when you start looking at all the incident edges on E, well you find a back edge that goes to a visited node B. Well the other edge is also a back edge that goes to node D, but there is a new unexplored edge discover it and find F visit F. Well from F if you go to D this is what depth first search is about. You visit D from F and not G from E and that leads to do another back edge, a forward edge from F to G and again back edge from G to E. There is one more traversal left as you go trace back that is from B to D that again gives you a back edge. So, we have marked different discovery and back edges here. The properties of DFS well it visits all the vertices and edges in the connected component GV containing V and as I pointed out earlier the case of BFS you are going to run your DFS on a V1 or a V2 for every connected component GV1 or GV2 and the edges label discovery by DFS in every such connected component forms a spanning tree TV of GV. So, this gives you spanning tree TV1, spanning tree TV2 and so on. Some analysis of DFS each vertex is labeled twice and that gives you order of V complexity. One is when you make it unexplored and the other is when you visit and market as visited we never visit a visited node. In fact, what we do is look at all the descendents of a visited node until they are completely explored. Each edge is also labeled twice the first time the market is unexplored the other is to either market as a discovered edge or as a back edge. So, this gives you basically order of V plus E complexity the G dot incident edges is called once for each vertex U over all the incident edges that also gives you order E. So, overall V plus E applications well making use of all the bookkeeping and the implementation using a stack that we discussed you could solve certain problems in order of V plus E complexity and these happen to be problems that are more natural with DFS than with BFS. So, of course, you could find the path from vertex V to U by invoking DFS GV. This you could keep track of by looking at pi U and then pi of pi of U and so on look at all the parents and thereafter all the ancestors. You could also detect cycles that is a very important contribution of DFS. What you need to do is invoke DFS GV for any V and keep looking for a back edge. So, existence of a back edge means there is a cycle. Can you find all the cycles? Well if you look at the example that we showed there are multiple DFS instances where back edges were found. So, indeed you can enumerate several back edges by doing a DFS on the entire graph rooted at V instead of stopping at the first instance of a cycle. I leave it as a homework problem for you to determine if you can find all the cycles. DFS is also the classic strategy for exploring a maze where basically you are doing backtracking search. So, it makes sense to do DFS instead of BFS because you are not interested in all the paths that lead to the goal, but you are interested in one path and exit through that and DFS has been for that. Thank you.