 Hello and welcome back. In this lecture, we are going to study about the template class list as a part of the C++ standard library. Here is a quick recap of some of the relevant topics we have been studying. We have been studying about template classes and functions and specifically in the C++ library, we have seen the string class, the vector class and the map class. In this lecture, we are going to study about the template class list. Now the template class list actually represents doubly linked lists. So let us first try to understand what doubly linked lists are. A doubly linked list is basically a data structure or representation of information in which different data items are linked to each other. So here I have four different data items which are represented by these rectangles in the middle and I will call this the front of the list and I will call this the back of the list and each data item has a link, usually a pointer to the next data item in the list and also each data item has a link or pointer to the previous data item in the list. So here the arrows pointing from left to right are the forward links. They allow us to move from one data item to the next data item whereas the arrows from right to left are the backward links. They allow us to move from one data item to the previous data item. So usually a linked list will have a data item along with some additional members which are used to store links or pointers to either next or previous data items. So that's what a generic doubly linked list looks like. It's called doubly linked because from every data item there is a link to the next data item as well as a link to the previous data item. Now doubly linked lists are actually a very convenient way to represent dynamically created sequences of objects or data items. The memory allocated for consecutive objects in the list are not necessarily contiguous and they may not even be allocated at the same time. Now what would happen to the previous element link or pointer of the front of the list and what would happen to the next element link or pointer to the back of the list? Well depending on the implementation these might be set to null or to other specific values. When we are using the template class list from the C++ standard library we absolutely do not need to worry about what these dangling links or dangling pointers are pointing to. Now if you have a doubly linked list it's actually fairly easy to see that you can very efficiently delete objects from the list. In fact you can delete objects from the list in constant time. Suppose I wanted to delete data item 2 from this doubly linked list. All I need to do is to remove this data item and to reassign the forward and the backward pointers like this. So as you can see deleting an object in a doubly linked list simply amounts to reassigning the pointers and removing that element so this can be done very efficiently. Similarly insertion in a doubly linked list can also be done very efficiently. In fact once again it can be done in constant time. So for example suppose here this is a data item that I wanted to insert in this list at this position. So all I need to do once again is to reassign these forward and backward links so that the forward link from data item 1 points to data item 2. The forward link from data item 2 points to data item 3 and the backward link of data item 3 points to data item 2 and backward link from data item 2 points to data item 1. So as you can see these changes of links or pointers can be done very efficiently if I were to insert an object at a specified position in a doubly linked list. However if you wanted to access the nth element in a doubly linked list this is going to be fairly inefficient because you don't directly have a way to reach the nth element in the list you will actually require to traverse the list from its front. So for example if I were to access the third element in the list I'll have to start from the front of the list and that's the first element then I have to go from there to the second element using the forward links and from there to the third element using forward link again and only then would I be able to access the third element in the list. Now if you compare a list with a vector which we have already studied you will note that a vector also stores a sequence of data items or objects however in a vector the memory locations for the successive elements are contiguous memory locations they are allocated together at the same time. Insertion and deletion is much more expensive in a vector because suppose I were to delete data item 2 not only would I have to delete or remove the data item 2 but I would also have to copy data item 3 in the position of data item 2 and I have to copy data item 4 in the position of data item 3. So deletion would be much more expensive because it would require copying or moving data and similarly insertion is also going to be expensive because if I were to now insert a new data item between data item 1 and data item 2 then the size of the vector has to increase and whatever is now at the second position will have to get copied to the third position whatever is now at the third position will have to get copied to the fourth position and so on in order to be able to insert a new element between data item 1 and data item 2. So what you see is that insertion and deletion are really cheap or efficient in linked lists but they are much more expensive in vectors however accessing the nth element is extremely efficient in a vector it's a constant time because all the data items are allocated contiguous memory locations so once you know the address of the first data item you will actually be able to calculate the address of the nth data item and you can go and access that straight away. So accessing the nth element is efficient unlike in a doubly linked list where accessing the nth element is actually quite time consuming. So the choice of whether you're going to use a linked list or a vector for your purposes in your program really depends on the nature of your program. If you're going to do lots of insertions and deletions perhaps a linked list is a good choice. If you need to access specific elements by their indices a lot of times perhaps a vector is the best choice. For example for purposes of sorting where we actually need to swap elements insert elements in between two other elements and so on a linked list would certainly be a good choice. Now the list class is actually used for representing and manipulating doubly linked lists. This is a template class so it can be instantiated with the type of the data item that is going to be stored in the list and of course as the list grows or shrinks memory is dynamically allocated or deallocated. However dynamic memory management is built inside the list class so as a user of this class you will not need to worry about how memory is being allocated or deallocated. Like vectors and maps list objects are container objects they are basically collections of objects of some other type and if you are to use the list class in your program you must use hash include list at the start of your program. Like the vector class and the map class the list class also has a large collection of member functions. In this lecture we'll be able to study only a small subset of these. I strongly encourage all of you to study about the other member functions of the list class from the handout that is to be provided. Now here is a simple program that uses the list class. Note I have written here hash include iostream and I have also written hash include list. I have used using namespace std this is because the list class and all its member functions are in the std namespace and there in the main function I have declared three lists. The first one is a list of strings the name of that list is names however I have not specified the size of the list so this is basically going to create an empty list of strings. The second declaration says that this is also going to be a list of strings however this list whose name is books will contain three elements and each of those three elements which are strings will be initialized to Alice in Wonderland. The last declaration here basically creates a list of integers how many integers are there in that list there are 10 integers and each of those 10 integers in the list is going to be initialized to minus one. How do we find the size of a list? Well if I look at the three lists that I just created I could then print out their sizes using the size member function so in this particular case I'm printing out the size of the list names the size of the list books and the size of the list numbers and we know what their sizes are this is 0 this is 3 this is 10 so this is what is going to get printed out sizes colon space zero space three space 10. Now how do I add elements at the front or back of a list? The list class actually provides very convenient member functions for achieving this for example here I have created an empty list of strings and the name of the list is names so that's the empty list it doesn't have any element in it so far then I say names.pushback and I provide the string Abdul so basically this is going to look at the list names and it is going to add the name Abdul after the element at the back of the list now here the names list was empty so when we add the name Abdul after the element at the back of the list basically we are creating a list of a single element and that element is Abdul this is because names was an empty list to begin with however after having done that once I've got a list containing a single element note that the single element is both the front of the list as well as the back of the list so now when I execute push front Ajanta what it will do is it will push the string Ajanta to come at the front of the existing list so my list was Abdul so now at the front of that list I will have Ajanta so my list is now Ajanta followed by Abdul Ajanta is at the front of the list Abdul is now at the back of the list now if I say pushback Bobby this is the back of the list so Bobby is going to get added after Abdul so that's what I'm going to have and finally if I say push front Alex this is the front of the list so Alex is going to get added over here and so that is the final list of strings that I'm going to have after the sequence of four pushback and pushfront operations now we've just seen that these instructions basically create this list what happens if I say pop back so recall that this is the front of the list and this is the back of the list so when I say names.popback it is simply going to remove the element at the back of the list and I'll be left with the list Alex Ajanta Abdul this is the new back of the list and this is the front of the list now after that if I execute pop front what is it going to do it's going to remove the element from the front of the list so it's actually going to remove Alex and I'll be left with Ajanta and Abdul this is the new front of the list and this is the back of the list and finally if I execute names.pop front again it will again remove the element at the front of the list so in this case Ajanta will be removed and I'll be left with the list containing only the string Abdul now we have studied about iterators for container classes the list class being a container class also has its iterators and there are iterated related functions in the list class so just like for the vector and map class we have the begin and end member functions so here in this example I have created an empty list called names then I have added three strings to this list this is a list of strings of course so how have I added them I have first pushed Abdul in the front then I have pushed Ajanta in the front and finally I have pushed Bobby in the front so basically after these three instructions get executed Bobby is at the front the next element is Ajanta and the last element or the element at the back is Abdul now here is my iterator for the list class so I say iterator of the list class instantiated with the data type string and I call that iterator it and now I'm going to iterate through this list using this iterator it and how am I going to do that through the simple for loop where it is initialized to names dot begin so basically this will return an abstract pointer to the first element the element at the front of the list and when I do it plus plus I will be advancing through this list using the forward links and how long should I do this until it becomes equal to names dot end names dot end is an abstract pointer to something after the end of the list so until I reach there I'm going to iterate through this list and because it is an abstract pointer so I can use star it to print out the string at that appropriate list position as I'm iterating through this list so if I execute this code noting how my list was formed Bobby was at the front then was Ajanta and finally was Abdul so I'm going to get Bobby comma Ajanta comma Abdul comma the last comma comes because of this comma over here so that's what is going to get printed out now I could also have a reverse iterator which I could use with the R begin and R end member functions so here RIT is a reverse iterator of the list class instantiated with string data type and here I'm iterating through the list but in the reverse direction from the back of the list to the front of the list so when I say names dot R begin this is actually an abstract pointer to the element at the back of the list and as I increment the reverse iterator I'm basically following the backward links and moving from the back of the list to the front of the list and how long am I doing that until RIT becomes names dot R end so names dot R end is an abstract pointer that points to something before the front of the list so basically I will continue iterating in this loop until I have traversed all the elements from the back of the list to the front of the list and RIT being an abstract pointer I could use star it to print out the elements in the list as I'm traversing it in the reverse order so note how the list was formed here Bobby was at the front then was Ajanta and finally Abdul was at the back so when I print the list in reverse order I'll be printing Abdul comma Ajanta comma Bobby comma once again this last comma comes from here I can also insert an element in a list using the iterator so for example here is that little code fragment which forms the list that we just saw and then I could say that after this code fragment in brown is executed I basically have the names list looking like this Bobby is at the front then is Ajanta then is Abdul and then when I say IT is an iterator of the list class instantiated with the string type and IT is initialized to names dot begin basically the iterator IT is pointing to the front of the list that is to Bobby then when I say IT plus plus the iterator points to the next element in the list using the forward links so now IT is pointing to Ajanta and now if I say names dot insert IT Alex it will basically insert Alex just before where the iterator is pointing so that's where Alex will get inserted and note that IT is still pointing to Ajanta as it was prior to this insertion so the point to remember is that when I ask for an insertion using the insert member function it inserts the new item just before where IT was pointing and IT continues to point to the same element in the list so now if I try to print out the names in the list I will get Bobby comma Alex comma Ajanta comma Abdul comma here is another example of insertion in a list using iterator so this is the part that we just saw after the code that is shown in brown is executed I basically have the list Bobby Alex Ajanta Abdul and IT is still pointing to Ajanta so now what I could do is I could say IT minus minus so now IT is going to point to the previous element in the list which is Alex and then I could say names dot insert IT two comma Avi so this is basically saying insert just before IT so just before Alex some insertion is going to happen this two says insert two elements and each of those two elements are going to be initialized with a string Avi so basically this is what's going to happen just before Alex two strings both initialized to Avi will get inserted the iterator is still pointing to Alex so now if I try to print out the names in this list I will get this as up I could also remove an element from a list using an iterator so once again this part of the code shown in brown basically creates this list and IT is now pointing to Ajanta and then I say names dot insert IT Alex so Alex gets inserted just prior to Ajanta IT is still pointing to Ajanta and now when I say names dot erase IT Ajanta is erased from the list this is a deletion of an element from the list so the list that now remains is just this this is the front of the list and this is the back of the list so now when I try to print out the elements in the list I'm going to get this at the output Bobby Alex up now the list class also provides special functions to directly access the elements at the front and back of the list so for example here in the part of the code highlighted in brown I have created the list with Bobby at front then Ajanta and Abdul and back then we have seen this that the next part of the code basically inserts Alex between Bobby and Ajanta and finally this erase IT erases Ajanta so we basically have the list Bobby Alex Abdul and now in this list if I say please give me the front element please give me the back element I will get Bobby and Abdul so that's what I get when I try to print these out the front element is Bobby and the back element is up the list class also provides a member function for reversing a list directly so for example here the brown part of the code creates this list Bobby Ajanta Abdul and now if I try to print out this list using a forward iterator I will basically get Bobby Ajanta Abdul as the output but after that I could say names so this is a member function of the list class and what this is going to do is it's just going to reverse the order of elements in the list whatever was at the back will now come at the front and whatever was at the front will now go to the back and every element in between will get reversed in order so in our case starting from the list Bobby Ajanta Abdul we will now get the list Abdul Ajanta Bobby and now if I try to print this list using the forward iterator note I'm using the forward iterator again here as I had used here but the list has been reversed in between so using the forward iterator if I now try to print this list I will get the output Abdul Ajanta Bobby now so far we have actually seen lists of simple data types like strings or integers but the list class is really a template class and it can be instantiated with any data type I can even have lists of lists of lists and you can continue as long as you want so for example here is a list being declared which is a list of the three-dimensional vector class v3 that we had studied earlier here is another list named my list 2 which is a list of integer pointers so note that I have used a list itself to instantiate the data type of a list and of course when you are using lists of lists you should note that this space is important if you omit this space this will appear like two greater than symbols one after the other so that will be as if we are trying to read some input it's also called the streaming operator but we do not want that here so we must put the space here when we are trying to instantiate a list class with a list type itself so in summary in this lecture we studied about the list class we saw some of its usage but we could only study some features of it in the limited time we have there are several more features of the list class and I encourage all of you to study about these from the handout thank you for your attention