 So, this is about structures and pointers. So, of course, all of you know this that memory is you know every location of memory has an address and it stores one byte and every program that is run is allocated some chunk of memory which is divided into stack segment, data segment and code segment. And so, here I have a simple program in which there is a structure my struct type which has a character member and two integer members. And then I have declared two local variables P1 and A, P1 is of type my struct type and A is integer. So, since both P1 and A are local variables space for them will be allocated in the stack segment right in the activation record of main. So, and for A we will allocate 4 bytes of storage because it an integer requires 32 bits. So, in the stack segment I have 4 bytes for A. So, how many bytes would I need for P1, P1 needs to store P1 is an object of my struct type. So, it needs an integer it needs two integers and a character. So, that is each integer requires 4 bytes. So, it is 8 bytes plus character requires 1 byte. So, it is 1 byte plus 4 bytes plus 4 bytes. So, that is 9 bytes of storage and in memory it would look something like this that you know the in the storage allocated for P1 there would be 1 byte reserved for the member named Z, 4 bytes reserved for the member named X and similarly 4 bytes for the member named Y. However, if you notice that in this brace I have put here I have allowed some gap here and if you are wondering why did I allow that gap we will just see that in a minute. So, this is just saying that local variables are allocated space in the stack which we just discussed, but here when you are looking at the space allocated for P1 which is of my struct type you know this has 3 members Z, X and Y. Now, although most compilers will actually do this it will allocate the first byte for Z the next 4 bytes for X and the next 4 bytes for Y most compilers will do this because that is perhaps the natural way to allocate the memory. But the C++ standard does not require the compiler to do this for example, the C++ standard says that if the compiler wants it can put Y first then Z and then X. So, you should not make any assumptions about the relative layout of the different members within the memory allocated for the structure. You should not assume that the first byte is indeed Z and then the next 4 bytes are X or so on. If you want to access a member within a structure use the dot P1 dot X or P1 dot Y. Similarly, you know here some 9 bytes have been allocated for the structure and one might say you know why is this brace not ending here at the end of the 9th byte and this is because C++ standard allows the compiler to put some padding depending on the machine architecture. So, for example, it is possible that your compiler is actually storing maybe instead of 9 bytes it is actually reserving 12 bytes of which 3 bytes are unused. So, it can provide some padding the standard actually does not even specify where you put the padding at the beginning or at the end or in the middle. So, for example, here I have shown the padding at the end it could have come in the middle like this. So, you should not make any assumptions about within the memory allocated for a structure where exactly is your particular data member because it depends on the relative layout it depends on what padding the compiler has put and the standard allows all of these. So, you should not make any such assumptions you should access the members only through the specific operators like dot operator used to access the members. However, all the 4 bytes allocated for a particular integer member will be contiguous it is not that the 4 bytes allocated for p1.x will themselves have some padding between them. So, that will be treated as an integer however, between x and y they could be padding y could appear before x in the layout and so on. And I mean all of you would recall the ampersand and star operators for getting the address of a variable and for dereferencing an address. So, we can use exactly the same thing for structures for example, here I have shown a program where I am using the ampersand and star operator on integers and integer pointers. Here is an analogous program where I have defined a structure I have declared a variable of that structure and this is a variable whose type is pointed to that structure just like I can have pointed to an integer I can also have pointed to a structure. And just like I can take the address of an integer variable and put it in a variable whose type is in star. So, I can take the address of a variable of type mystruct type and put it in a variable whose type is mystruct type star. And then I can dereference star pointer pt1 since pointer p1 is of type mystruct type star. So, star pointer p1 would be an object of type mystruct type and therefore I can initialize it just like the way I would initialize any object of type mystruct type. So, this is exactly parallel to what we do over here with the basic data types like integer float character and so on except that we are now talking about user defined types rather than the primitive data types given by the language. I mean exactly the same no change at all. So, if you have understood ampersand and star for the basic data types this is exactly the same there is no difference. So, this we have already just discussed. So, can we access the individual members through pointers? So, for example, I know that star ptr1 accesses the object whose address is given by ptrp1 and it accesses this object as an object of type mystruct type. But suppose I wanted access to a specific member of that object let us say x or y. So, I could of course, say star ptrp1 dot x star ptrp1 dot y because star ptrp1 is giving me access to that entire object. So, then I could use dot x dot y and this is correct this is fine. However, C++ provides an additional operator called the arrow operator for these kinds of situations. So, basically instead of saying star ptrp1 dot x I could say ptrp1 arrow x. What this arrow says is you first dereference the thing to the left of it and after you have dereferenced you access the member named x. So, ptrp1 arrow x means dereference ptrp1 and then access the member named x which is exactly the same as star ptrp1 dot x. So, basically these two things are the same pointer variable arrow member name is equivalent to star pointer variable dot member name. However, the arrow operator can only be used with a pointer to a structure. Whereas the dot is used with an object of that structure the variable of that structure. So, that is the only difference. So, here I have shown some simple examples where I could initialize star ptrp1 ptrp1 which is the entire object directly like this or I could say ptrp1 arrow z is c ptrp1 arrow x is 2 ptrp1 arrow y is 3 and so on. Similarly, I could write this or I could say ptrp1 arrow x is 1 plus ptrp1 arrow y. So, they are two completely functionally equivalent programs. So, are there any doubts about this? You had some question here. So, this is dependent on the architecture of the computer that you know you are using more specifically on the architecture of the memory that you are using. So, there are processors which can access memory only at addresses which are multiples of 4, but you know there one can think of other processors. For example, I mean the C++ language can also be used for what are called embedded processors. These are processors that go inside your mobile phone or you know go inside small gadgets and their memory is very very expensive. You cannot waste memory. So, those processors will allow you to access memory at any particular address. So, that depends on that memory architecture. So, that is why you know when you are programming, you should not make any assumption that that there is some padding to align it with a multiple of 4 or there is no padding because it depends on what processor you are running, what compiler you are using, what memory architecture. So, as a programmer you do not want to bother about that. So, you are right. In some cases the addresses need to be multiples of 4, but not in all cases there are processors which do not require that. So, let us go to the next one. So, this is continuing our discussion on structures and pointers. So, here is you know a simple example of a, I mean we will actually build more on this example in the next set of slides that I will show, but suppose I am trying to implement a taxi queuing system. Once again this is inspired by some examples in Professor Ranade's book. So, here I have defined two structures, one to store information about the driver, the other to store information about a taxi. So, driver has a name which is a character array and there is presumably an integer id for the driver. A taxi has an integer id and the driver for the taxi can keep changing. So, we do not fix the driver with the taxi. We sort of allow a pointer to a driver object to be present here. So, that if the driver changes I can just change that pointer. And then I have declared two variables, both of these are local variables in the function main. One is of type driver, the other is of type taxi. So, you know how much space will I require for this structure taxi, id is an integer requires 4 bytes, brv is a pointer to the structure driver. So, pointer is just an address in memory. And if we assume that our memory requires 32 bits of address, then whether it is a pointer to integer or pointer to float or pointer to driver, all of them are just addresses. So, they will just require 32 bits 4 bytes. So, here I require 4 bytes plus 4 bytes, 8 bytes for an object of type taxi. And so, you know when I, so this being a local variable, d1 being a local variable of main, space for it will be allocated in the stack segment. How much space? The structure driver has requires 50 bytes for storing the name, each character requires 1 byte and 4 bytes. So, here I have tried to depict here of course, this not to scale, but the name requires a little bit more storage 50 bytes than id which requires 4 bytes. And then taxi t1 is also a local variable. So, it will also be allocated space in the stack segment. And this requires 4 bytes for id and 4 bytes to store the address of a driver. So, they are that is kind of like this. And then suppose I have a code which says d1 is assigned shaker 23. So, what this will do is this is initializing a variable of type driver. So, the name member will get the value shaker, the id member will get the value 23. And then suppose I say the id member of t1 is assigned 12 and the drv member of t1 is assigned the address of d1. The drv member is of type driver star. So, it can take the address of an object of type driver. So, d1 is an object of type driver. So, it can take the address of t1. And what do we mean by the address? It is once again the address of the starting byte. So, let us say that is 230 in hex. So, we will get 230 over here. Now, from now onwards, we will actually have a lot of occasion to talk about some member of a structure containing the address of some other structure just like we have here. This drv is a member of the structure containing the address of another structure. And instead of sort of writing the address here and then copying that address there and then sort of carefully looking at it and figuring out that this is really the address of that. What we will do is we will often use just this more convenient notation. We will put an arrow like this from here to here saying that this is really pointing to the there which means that drv has the address of d1. d1.drv has the address of d1. So, we will use this notation quite frequently. So, now what we want to have is we want to implement a queue of taxis. So, we want one taxi to point to the next taxi and then that taxi to point to the next taxi or one taxi from one taxi I should be able to get information about the next taxi so that we can have a queue. Now how could we do this? Could we do it like this that this is the struct link taxi has the id and the driver pointer but can I put next and can I put a link taxi over there? So, this will have the same problem that we discussed earlier that the storage required for this would be some 8 bytes for this and the storage required for link taxi which will again require 8 bytes for this and the storage required for another link tax and that will continue forever. So, we cannot do this because it would require infinite storage. So, then how are we going to have one taxi sort of allow us access to the information about the next taxi. So, one easy way of doing this is to actually have instead of saying that I am going to actually have a copy of the next taxi structure let me have a pointer to the next taxi. So, here what I have done is in the link taxi structure I have the id and the driver pointer as earlier but instead of next being the link taxi itself now I have made next a pointer to the linked taxi. So, the type of next is link taxi star and this does not have a problem because they said it does not matter it is a pointer to what it requires this 4 bytes a pointer is just an address. So, here the total number of bytes required is 4 plus 4 plus 4 that is 12 unlike the previous case where I required infinite storage. So, now what I could do is I could have a program like this where I am saying that the driver is the same structure as before link taxi is what we just saw it has a member next which is a pointer to the next link taxi and suppose I have two variables d1 and d2 of type drivers. So, they will be allocated space on the stack segment and then I have two variables d1 and d2 of type taxi they will also be allocated space on the stack segment and then I initialize d1 with shaker 23 so that is what happens here d2 with Abdul 34 so that is what happens here in the space for d2 and then I say d1.id is 12 d1.drv is the address of d1 so that is this arrow notation I am using here. So, t1.drv is pointing to d1 which means it has the address of d1 and t1.next is null so the next is 0 and then I say t2.id is 11 t2.drv is ampersand d2 so t2.drv is pointing to d2 and t2.next is ampersand t1 right link taxi next is of type link taxi pointer. So, t1 is an object of type link taxi so ampersand t1 will be link taxi pointer so I can assign that to t2.next. So, now you have this situation where in t2 there is this pointer pointing here and then there is this pointer pointing there and now I could ask can we print out t2.next arrow drv arrow name so what does this mean it means go to t2 access the next member dereference that then access the drv member right the arrow means dereference the left hand side then access the member on the right hand side so t2.next is here dereference that so go to wherever it is pointing then access the member named drv but then there is one more arrow so dereference that go to where it is pointing and access the member named name right so that gives a shaker okay and we have also used nu and delete with basic data types like integer float character and so on we can use the same things here so for example I could say nu driver which will allocate an object of type driver on the heap dynamically and it will return a pointer to that or I could similarly allocate an array of drivers so this is just like allocating an array of integers right. So, if it was an array of integers I would say nu int2 here I am saying nu driver 2 because driver is my user defined data type so this will allocate space for an array of two elements where each element is of type driver and will return a pointer to the first element to my drv array and similarly like delete right if you want to say delete my drv pointer then it will see wherever it is pointing to in the heap and it will delete that and if you say delete an array it will delete their entire so this is just like what we did for basic data types except now we are doing it for structures right so this is the nice part that if you have understood things for the basic data types understanding it for structures is the same there is no additional effort required and of course you have to be careful about the usual things that if you are that nu may not return successfully so if after you have dynamically allocated something and before you are dereferencing that address you should check whether that is not null and if it is null maybe you should print out an error message saying that memory allocation has failed and similarly when you are trying to delete something you must first check that it is not null and then delete that this is the usual thing which we had for pointers to basic data types also so now what we will do is we will just look at an example which applies all of these things that we have just studied right so in this example we are actually going to implement the taxi queuing system the full blown taxi queuing system so this is think of a situation where you know taxis are arriving and departing at different times maybe at a train station and we want to maintain a queue of these taxis and the queue has the usual expected you know properties that the taxi that came earliest will be at the front of the queue and this will be the taxi that will be dispatched next the taxi that came latest will join the queue at the end and it will stay in the queue until it reaches the front and is dispatched it is what you would expect in a taxi queue so here is how I can sort of implement it so these are the different structures I am going to use the driver and the link taxi that we have already seen instead of a character array I have used the data type string here which we had mentioned I think in the second or third lecture of the course but if you are more comfortable with character arrays you can also use character arrays this is just for some convenience I have used string there the link taxi structure is exactly the same as we had seen it has a pointer to the next taxi and queue is going to be a structure which has a pointer to the front and end of the queue because I need to dispatch taxis from the front and I need to add taxis new taxes at the end so I need to know where the front and end of the queue are and it also contains a count of the number of taxes in the queue and so note that all of these structure definitions are before the functions that use them and of course outside the functions because they are going to be used in multiple functions this is the string and now here is the main function it allocates an object queue of the type queue and to begin with the queue is empty so we denote that by saying both the front and end are null and the number of taxes is 0 so note that I am accessing the members through the dot operator because I am directly using an object of type queue not a pointer to object of type queue and then here is a simple loop so you know suppose this program is running at the counter from where taxis are being dispatched so at the counter perhaps there is an operator who is giving in different commands to maintain the queue so what are the commands if a new taxi has come to join the queue so j a new passenger has come to take a taxi from the queue so the dispatch or you exit and then this is fairly simple I am reading in the command and then using a switch case statement if the command is to join I will execute the code to add a newly arrived taxi at the end of the queue if the command is to dispatch I will dispatch the taxi in the front of the queue otherwise I will exit and then you know although this is a while true loop looks like an infinite loop but really by typing x you can exit from this loop and also exit from the program so that's straightforward so now let's look at the code for adding a taxi at the end of the queue and for dispatching a taxi from the front of the queue so this is adding a taxi at the end of the queue so a new taxi has come it has to be added at the end of the queue so I first allocate an object of type driver and then of course if that allocation failed I print out this and return minus 1 otherwise I read in the name of the driver read in the name of reading the id of the driver a driver has a name and id then I allocate an object of type link taxi and then make the drv member of new taxi which is a pointer to the driver right so I make it 0.2 whatever this new driver had allocated I make the drv member point to that I make the next member point to null because this is going to be the last taxi in the queue so it's after it there is nothing and then I read in the id of the taxi and then I have to now add it to the queue right so how do I add it to the queue so there are two cases one is the queue is empty and the other is the queue is non-empty so the queue is empty it means both front and end where null so if that is the case I am just going to add this taxi and this will be the only taxi in the queue now because the queue was empty and now I am adding a taxi to the queue right so if it's the only taxi in the queue I make both front and end point to this taxi I update the number of taxes in the queue to 1 and that is it so from an empty queue now I have gone to a queue with one taxi right is that clear so this is the simpler case how to add a taxi to a queue which was empty the other case is when the queue was non-empty so let's say the queue already had a blue taxi and a red taxi the blue taxi was the front the red taxi was at the end and of course the next of the blue taxi is pointing to the red taxi the next of the red taxi is pointing to null and now here is this new yellow taxi that has come which has to be added at the end of the queue so what do we need to do to add it at the end of the queue the red taxi's next pointer should point here and q dot n should point here so that's what we'll do the red taxi's next pointer should point here and q dot n should point here which means whatever was q dot n earlier its next member should point to new taxi and then q dot n should itself point to new taxi right so that's exactly what we have done q dot n's next member should point to new taxi and q dot n should itself point to new taxi okay so note here I have used a dot here because q is an object of type q so to access a member I can use dot but the end member of q is a pointer to the linked taxi so then to access its next member I have to use the arrow right q is an object so I can directly use q dot end but q dot end is a pointer so I have to use the arrow over there okay and I increase the number of taxis so that's how we add a taxi at the end of the queue how do we remove a taxi dispatch a taxi from the front of the queue we first figure out what is the taxi at the front of the queue so dispatch taxi is q dot front and of course first we check whether there are any taxes in the queue at all if there are no taxis then we can't do anything otherwise we take the taxi at the front of the queue and if this was the only taxi in the queue which means q dot front was equal to q dot end then after we dispatch this taxi the queue is going to become empty so we have to sort of reflect that so both front and end become null and num taxi is zero so this is the simple case if there was only one taxi in the queue you dispatch it and the queue becomes empty otherwise what happens is there are only three taxes in the queue the blue red and yellow and I want to dispatch this one at the front so after I have dispatched this q dot front should point here so that's what I'm going to do I'll say q dot front should point to the next of whatever q dot front was pointing earlier that q dot front was pointing here so the next so q dot front should now point to wherever q dot front is pointing and where next of that is pointing and I decrease the number of taxis and then I have to sort of get rid of this dispatch taxi from the you know I mean this is no longer needed this taxis now dispatched so I can free up this memory this was dynamically allocated when the blue taxi had joined the queue so I can free up that memory so I say that well you know I'm dispatching this taxi and then I want to delete dispatch taxi but remember this dispatch taxi itself as a pointer to a dynamically allocated driver object so when I free up the taxi I should also free up the driver object so that's what we do for the driver object free up the memory for the taxi so that's what this was about so so this example if you think about it it actually made use of linked structures which is a very important concept when you're talking about you know dynamically maintaining information it had dynamic allocation, deallocation it used member accesses through both dot and arrow operators and one interesting thing was that the size of the queue was not predetermined I did not allocate an array of size 100 and say that the queue can only have up to 100 taxis right so the size of the queue was really determined by how much memory you had as long as memory can be allocated you can keep adding taxes to the queue okay then let's go to the quiz then okay so this is the first question which of the following is or are legal struck definitions in C++ so we've just discussed this in great length okay so here is a piece of code in which I have defined a structure here and then I have dynamically allocated an object of that type and x is a pointer to the dynamically allocated object and let us say that this new allocation happens successfully which means an object is actually allocated and then I want to initialize the two members of the newly allocated object to 20 and null the member a which is an integer I want to allocate I want to initialize it to 20 and the member next which is a pointer I want to initialize it to null right so this is a structure definition this is dynamically allocating an object of that type and here I am trying to initialize the members of the newly allocated object so what should I use for x1 and x2 okay the next question so this is structured p1 has a character and two integers have allocated an object of type p1 so the number of bytes allocated for this object is best represented by which of these options this also we have just discussed so this is a structure which has two integer members and then I allocate an object of that structure dynamically and x is appointed to that so suppose that new successfully allocates and then I want to access the member a of the dynamically allocated objects which of these options will allow me to access the member named a of the dynamically allocated object and this is just to see if you are awake in the last few slides so which of the following are true of the taxi queue example that we just studied the maximum number of taxis is predetermined dynamic allocation the allocation of structures is used an array of linked taxis objects is used and all linked taxis objects are allocated on the heap okay so let us quickly discuss the solutions for these these are fairly straightforward so which are legal struck definitions so this cannot be legal because this is kind of like a recursive definition it will require infinite storage this is fine it has a pointer to t2 this cannot be fine because once again it is recursive and will require infinite storage and this is also fine just as pointers so this is accessing members through a pointer x is a pointer to the newly allocated object and I am trying to access members of that newly allocated object through that pointer so this is how you access members through the arrow operator once you have a pointer the number of bytes is of course you need at least nine but as we just discussed it is really at least nine because the compiler can allocate more bytes right here you are trying to access the member a through the pointer x so certainly x arrow a will work but star x dot a will also work right because star x will dereference the pointer and will give you the object and then you can access the member a and here of course the maximum number of taxes is not predetermined dynamic allocation deallocation is used we are not using an array and everything is dynamically allocated on the heap right okay good so now let us go to the practice question so so in the last lecture we actually talked about binary trees right so what I want to talk about today is another kind of data structure which is the way we represent information and these are called directed graphs and I guess the picture says it all I mean what is a directed graph it is a collection of nodes and some directed edges between them what do I mean by directed edges and edge has a tail and a head right so every edge is like an arrow it goes from one node to another node so here I have just sort of assigned some integer ids to the nodes but and a node that you know I can have a directed edge going from one node back to the same node and so on right so this is what a directed graph is I think this is fairly intuitive what it is right it is nodes and edges between nodes so these are the nodes those are the edges and here I have thrown in another node which is like a loner sitting there so so note that you know I could have nodes like this which have only outgoing edges which don't have any incoming edges I could have nodes like this which have only incoming edges don't have outgoing edges I could have nodes which neither have any incoming edge nor have any outgoing edge or I could have nodes which have both incoming edges and outgoing edges and note that the number of incoming an outgoing edges is not fixed to 2 or 3 or something like that, I could have as many incoming edges as many outgoing edges. Now, it turns out the directed graphs are actually of significant importance in a lot of computational problems and I am sure in your further studies you will encounter this sometime or the other and interestingly did you know that Google which all of us use almost on a daily basis treats the entire web as a directed graph where the nodes are the web pages and the edges are links from one page to another. So, this could be www.itb.ac.in, this could be www.csc.itb.ac.in if the main page is referring to the CAC page and that could be maybe your home page under the CAC page if there is a link from the CAC page to your home page. So, really at the back end of what is happening in Google are directed graphs, travel portals like make my trip or Yatra or whatever, clear trip is that. So, they also represent connections between cities as a directed graph where the nodes are cities and the edges are different kinds of connections available road connections, rail connections, direct flights and so on. So, as you can see these directed graphs are kind of quite pervasive in a lot of you know problems in a lot of things that we use in our daily lives also. So, what we want to do in this practice question is we want to write a program that reads in a directed graph and how does it read in the directed graph it basically reads in information about nodes and edges and then it constructs this directed graph in memory. How does it construct the directed graph? Each node will be represented by a particular structure and I am going to show you what that structure looks like and for the time being you can assume that the total number of nodes is fixed. So, you can assume all the nodes in the graph to be stored in an array named nodes. Of course, this is not going to work in a setting like Google where you cannot say the total number of web pages in the world is fixed. There are more web pages being created and deleted even as we speak. So, you know this is not how real applications will work where the number of nodes are dynamically changing, but at least for this first problem let us try to see how we can solve this problem by assuming that the number of nodes is fixed and then I mean if we are able to solve this problem the next version would be to remove that restriction. So, we will assume that the nodes are stored in an array named nodes and the ID of a node which is the number I had shown inside each node will be its index into the array just to simplify things. So, this is the structure of a node that we want to use. So, struct my node it will have the integer ID and it will have two other members called incoming and outgoing which are pointers to some type called linked nodes and of course I have used linked nodes here to sort of resonate it with the linked taxis that we just saw. So, this should be something similar to the linked taxis, but this is something that you should define ok. So, I want the struct node I want struct my node to be like this, but this is something that you should decide and define such that from a node I have access to all the other nodes to which edges are going out. So, those are the outgoing nodes and I have access to all the nodes from which edges are coming in. So, that is the incoming nodes and now this is kind of the program that I want to write. So, you need not copy this entire program, but please try to understand what we want you to do in this program right. So, here is the main function there is a variable called num nodes I am reading in the number of nodes and then I am dynamically allocating an array of that many number of nodes right. So, this statement is saying that nodes is of type pointer to my node where my node is that struct that you just copied down in your notebook and I am allocating an array of these many elements num nodes elements where each element in that array is of type my node. So, basically I am allocating an array of my nodes and returning a pointer to that returning a pointer to the first element in that array nodes right and we have seen about dynamic allocation of arrays earlier. So, if this dynamic allocation succeeds I can say node 0, nodes 1 and I can access the individual nodes in the array is that clear and then there is this little check here to see if that allocation succeeded and I would like to emphasize that any time you do dynamic allocation of memory you must do this. This is you know kind of good practice like taking a bath every day right. So, I mean so, your program may run today without putting in that check, but sooner or later you will encounter problems if you do not put in such checks ok and so, this is just saying that well if the allocation did not succeed I can just print out a message and come out otherwise I want to do some initialization on the nodes. So, this is something that I want you to write right. So, I mean you do not need to copy this entire program, but you know this is something that I want you to write. I want you to initialize the nodes after I have dynamically allocated the array of nodes right. So, we will see this function again in the last slide. So, you do not need to worry about it, but just remember that init nodes is supposed to initialize the nodes immediately after they have been dynamically allocated ok. After we have done that I am going to read in the edges ok. So, how am I going to read in the edges? I have two integer variables, this is kind of the start of the edge and this is the end of the edge. So, at the start of the edge is a node, at the end of the edge is another node. So, I am going to read in the two things. So, here I have a while true loop which reads in edges one at a time. It asks for the start of the edge or minus 1 to quit you do not need to worry about that. So, if it is minus 1 you can break from this while true loop. So, you basically read in the start a start of the edge and you read in the end of the edge and then you call this function which takes the nodes array takes this start of the edge which is the index of the node at the start of the edge, end of the edge which is the index or ID of the node at the end of the edge and it should do something to your data structure such that this edge gets registered in your representation of the graph right. Basically, this add edge function should do something such that later on when you look at your representation of the graph you are able to figure out that there is an edge from this node to this node. So, this needs to update something in the representation of the graph that we are going to use such that we can later recognize that there is an edge from start edge to end edge right. And finally, you know we can come out of this loop by put tapping minus 1. So, once again there is no need to copy this thing, but just remember that I will ask you to write this function and the purpose of add edge is to do something to your representation of the graph. Remember our graph is represented as an array of nodes and each node has an ID and it has some incoming and outgoing. So, you have to do something to that representation such that you register the fact that there is an edge from this node ID to this node ID. And finally what do we want to do after we have read in all of the information and registered them in our representation of the graph we want to read out that information. So, if we have registered things incorrectly then you will not be able to read things out correctly right. So, how do we read out? We are just going to iterate over the all the nodes in the array. So, for i is 0 i is less than num nodes i plus plus and for each node i I will print out the other nodes to which it has edges and I will print out the nodes from which it has edges right. So, print out node nodes i this is a function that you are required to write. This will take the index of a node and will print out all of those nodes to which this has an outgoing edge and print in nodes nodes i will once again take the index of the node i and will print out the IDs of all those nodes from which there are incoming edges to node i. Is this clear? Once again there is no need to copy down this program because what I am asking you to do is this thing. So, you have to first define that linked nodes structure which all of you have copied down right which must be used inside my node structure and then you have to write these functions and I hope that from the name of the function it is clear what I am asking you to do. This is initializing the nodes immediately after dynamically allocating the array adding an edge as you are reading an information about the edge and printing the nodes to which there are outgoing edges and printing the nodes from which there are incoming edges. Is the problem clear to everybody or is there a doubt about the problem? Yes, there is a doubt? Yeah, so init nodes is a function which does not return anything. So, its type is return type is void. So that function is supposed to take the array of nodes that has been dynamically allocated. This is the total number of nodes in that array and it is supposed to initialize everything. I mean certainly as part of the initialization you will have to set the ID of a node at index i to i right, but you will probably need to do a few more things. The function's name is init nodes and it is supposed to initialize all the nodes in the array. So, here I am dynamically allocating an array of suppose num nodes is 200. So, I am dynamically allocating an array of size 200 where each element in that array is an object of type my node. Now each object of type my node has all of these members. So, these members will need to be initialized for each object of type my node in that array. So, init nodes is supposed to do that. It will take in the array, it will take in how many elements there are in the array and then it should initialize each element appropriately right. So, that the ith element in the array really represents node i right and note that this is before I have read in the edge information. You should do the initialization assuming that the graph just consists of nodes no edges and then as you are reading in the edge information you have to update the information that is stored and once you have updated you should be able to read it out is that clear. So, nodes is an array right I mean there is some doubts about from some people. So, I have allocated an array here nodes is an array of nodes also said that here assume all nodes in the graph are stored in an array named nodes. So, nodes is an array. So, what Archit has done is he has said that so he has defined struct link node as a Boolean array and I believe some of you have also done this and then he has given int size right. And so, the idea that Archit has is that in the init function he is going to allocate this array. So, his init function looks something like this init nodes you know whatever my nodes and whatever. So, he says for int i is 0 i less than num nodes i plus plus and then he says nodes i dot id is assigned i. So, this is fine right the ith node in the array should have the id i the ith node in the array should have id i. And then what he says is he says nodes i dot outgoing is new bool num nodes. And similarly nodes i dot incoming is new bool num nodes. So, he is basically allocating two boolean arrays of size num nodes and then he has a little loop here which goes and initializes all of those elements in those arrays to false. So, the implicit representation that he has is that if in nodes i dot outgoing if the jth element is true then there is an outgoing edge from i to j. And if in nodes i dot incoming the kth element is true then there is an incoming node from node k to node i and so that that is true. So, this cannot be bool star. So, this has to be new linked node right and so, Archit there is a mistake that you have done here. This should be new linked node and then once you have this allocated then you can go to outgoing and you can access the array member of outgoing and you can allocate num nodes boolean array of size num nodes right. So, basically you have to say nodes i dot outgoing arrow array right and then he has done adage and print out nodes and print in nodes based on this. So, how many of you did a similar thing? Some of you I know have been, huh, interay instead of a bool array somebody has done an interay. So, that is good that is a similar thing, but do you see the problem with this? I mean it is okay it is a working solution, but this has got nothing to do with linked taxis right which I was trying to emphasize all throughout yeah. So, the problem with this is that you have to I mean maybe each node has just one incoming edge and one outgoing edge, but and let us say the total number of nodes is one million. So, here you will still need to allocate a boolean array of size one million for each of the one million nodes whereas just one element of those arrays will be used right. So, this is a bit wasteful of memory, but it is a correct solution for small graphs it will work. Now there is another solution which so both of them have actually come out with this other interesting solution which is to say that struct link node is has a my node pointer and call it whatever call it node and it has link node pointer next at least that is the solution that Neel had is your solution also something like this or it is simply a my node. So, you are going to make a copy of that which is a bit more wasteful right and so now you can use this to actually build like this queue of taxis now you can build a chain of nodes right essentially I mean if this was your my node this has an integer id and it has something incoming and it has something outgoing and this incoming is a pointer to link node right. So, it will basically point to something which will have a node here and a next here now this node is going to point to a similar thing like my node right id in out whatever this is another node and this next will now point to another linked node next to the pointer to link node which will have node here and next here and this node is now going to point to another my node. So, these are the things that are there in the array these are the different my nodes in the array and these are just pointing to those and now starting from a node I can just traverse this list and I can figure out all the nodes from which there are incoming edges right and similarly I can do this right and if you note a bit closely actually I do not even need this my node star node over here I can just put the id of the node because the id is the index in the array right the id is the index in the array of nodes how do we know because as I am adding edges I am actually giving the id of the start node and the end node right that is how I am giving the edges I am saying an edge from node 5 to node 37 and edge from node 29 to node 32. So, those are directly the id's right so I could just say int over here and that itself would suffice ok. So, here is you know a possible solution that you say struct my node struct linked node and you give int id and you say linked node next right and then in your init actually interestingly I saw some people have already written init nodes without defining linked nodes and their init nodes are correct because all that they have done is they have said whatever that for loop is there for i is 0 to this and that. So, they have said nodes i dot id is i and nodes i dot incoming is null so without actually defining what linked nodes is they have just set this to null and similarly nodes i dot outgoing is null. So, this is fine I mean if you are so this is actually fine for example, if these are going to be chains of node identifiers just like what I showed here these are going to be chains of node identifiers initially I want to set them to null. So, they are not pointing to any chains and then as I am adding a chain it is like adding a taxi at the end of the queue right I create one entry like this make them point to the right thing and add it at the end of the incoming queue or the outgoing queue