📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

Complete C++ STL in 1 Video | Time Complexity and Notes

take U forward1:07:37

Transcription

Hey everyone, welcome back to Take You Forward. So, in this video, we are going to learn about C++ STL. What is STL? STL is basically Standard Template Library.

Now, in order to write codes in C++, assume you're going to use a container or an algorithm. A lot of times, what happens is you don't need to pre-define the container or write the long, long codes for that container or for an algorithm. So, STL is basically a compilation of algorithms, containers, iterators, functions in a minimized version so that you don't have to write lengthy lines of code, and you can use that STL and you can get access to a container or to an algorithm. So, in this video, I will be teaching you all the STL that is actually required to get started with DSA. So, please make sure you watch this video till the end to understand or to learn C++ STL in depth. So, without wasting any time, let's get started.

So, let's understand the skeleton of a C++ code. So, you can see this is the entire skeleton of a code. And the first line is `#include <bits/stdc++.h>`. Generally, this is nothing but a library. And you would have learned about something like `math.h`. So, in order to include all the algorithms in the math library, you have to `#include <math.h>`. Similarly, in order to include all the libraries in string, you have to give `string.h`. Similarly, if you are wanting to add anything, you have to actually write `#include <library.h>` name for sure.

Now, imagine you are writing an algorithm or a program where you require a bunch of libraries. So, you cannot actually waste a lot of time in including all the libraries individually. So, what C++ tells us, "Okay, hey, listen, I have all the libraries inside this `<bits/stdc++.h>`. So, just include this one, and all the libraries are automatically included, and I don't need to individually add them."

Now, this is the `main` where you actually write the entire lines of code. Now, what is this actually for? `using namespace std;`. Now, imagine, just for a case, imagine I write `cin >> a;` and `a` is an integer. So, this works. But if you just omit this line, this will actually give an error. Now, if you don't add this line, you actually have to write `std::cin >> a;` or `std::cout << a;`. This basically takes an input into `a`. This basically prints `a` into the screen. So, if you don't write `using namespace std;`, you have to write this every time. So, that's again a hectic process. So, that is the reason what we do is we write `using namespace std;` and we omit this. But if you want to know about more in-depth, you can definitely read a lot of articles. I'll be leaving a link of an article in the description below. You can check that out.

So, before moving to the STL part, let's understand functions. So, there are a couple of functions. One is the `void`. So, if you write `void print()`, and over here you give `cout << "My name is Raj";` and I call the `print()` function. So, what happens is this `print()` function calls, and this will output "Raj" on the screen. Now, this is a `void` function. What does a `void` function mean? It will not return you anything. Okay? So, that is one kind of function.

And the other kind of function is a return type function. Assume I write `int sum(int a, int b)` and I say, "Can you please return `a + b`?" And over here, I say `int s = sum(1, 5);`. So, what happens is it calls this function, passes 1 into `a`, passes 5 into `b`, and returns `a + b`. Yes, and it returns `a + b`. So, you get `a + b`, that is basically 1 + 5 = 6, into the `s`. And now, if you do `cout << s;`, what happens is this actually prints 6 into the screen. You need to understand this. Now, this is a return type function, right? Now, this can be a `double`, this can be anything. Like, you can use any data type as you wish to. So, these are the basic stuffs about the C++ skeleton of a code.

Okay, so before moving to the next part of the video, I'd love to thank the sponsor of this video, which is Coding Ninjas. Coding Ninjas is India's... Now, why Coding Ninjas? Because their courses are well-structured, so learning. And also, the courses are very well-curated because these courses are prepared by people who have been at IITs as well as Stanford, and by the people who have been at Amazon, Facebook, and Google. Now, if you don't believe it, you can check out the Facebook as well as the Google rating of Coding Ninjas. The best thing about them that I find personally is the doubt resolution time. Like, the average doubt resolution time in the last one year has been 10 minutes. Like, if you're raising a doubt, it gets solved within 10 minutes. So, that's amazing. That's the most amazing thing that they do provide. So, if you are looking out to buy any of the courses, you can check out the link in the description. You can easily get an additional 20% discount on whatever price that has been going around. So, guys, make sure you check out Coding Ninjas. The link will be in the description.

Now, it's time that we move into the actual part, that is the C++ STL. So, you need to understand that C++ STL is divided into four parts: the first being algorithms, the second being containers, the third being functions, the fourth being iterators. So, as of now, we will be learning about containers. It can be `vector`, it can be `queue`, `set`, `map`, and a lot of other things. And we, during the course of learning containers, I will be also teaching you what are iterators. So, these couple of things we'll be learning at first. After that, I'll be talking about different algorithms and different functions that do exist in C++ STL.

So, before moving on to containers, you have to actually learn about pairs. Now, what is pairs? Pairs is a part of the utility library. Okay? Now, imagine I say that I want to store a couple of integers, like, I want to store 1 and I want to store 3. So, the only way that you can do is you can store it in a pair. Now, how is pair defined? You define the `pair` stuff, and then you say the first thing that you want to store is of integer data type, the second thing that you want to store is of integer data type. Then you enclose them into curly braces. So, what happens is this actually stores everything into a variable `p`. So, this variable `p` is now having `1, 3`. That is the meaning of this particular line. So, that's how you define. Now, in place of this `int`, you can also have something like `double`, `string`, `char`. The data type can be anything. Okay?

Now, if `p` is storing something like `1, 3`, now if I'm accessing `p`, it's actually a pair. What if I want to access this 1? What if I want to access this 3? So, it's very simple. What you say is, you just write `p.first`. `p.first`, and that will go and access this particular 1. And if you write `p.second`, that will go and access this particular 3. So, that is as simple as it can get. So, if you are printing `p.first`, 1 gets printed. If you are printing `p.second`, 3 gets printed. I hope this is clear.

Now, imagine you are wanting to store. So, as of now, you know that if you declare an integer data type or a string data type or a character data type, you can always store a single variable. Like, if I want to store `int a = 2;`, that's fine. And I also know if I want to store two variables, I can use something like `pair`. But what if the question comes up and they say that, "Let's store three variables, four variables, five variables." Can you do it? Yes, we can do it. We can use the nested property of pair. Yes, we can use the nested property of pair.

Imagine I say you that you're going to store 1, 3, 4. So, what you'll see is, "Okay, I have one pair, and I know this pair can store two guys. So, this is the first guy, and the second guy in a pair." So, what I'll say is, "The second guy can be of a paired data type." Thereby, the second guy stores two guys in itself. That is how you can do it if you're wanting to store three variables. Got it? Like, `pair<int, pair<int, int>>`. So, in the second guy, you say that I'm going to store a pair in itself. So, basically, `1, {3, 4}`. So, that's how you can also store three. And eventually, if they're asking you to store four variables, you can go nested, nested, nested, nested. That you can improvise. Okay? So, that's how you actually store more than two variables in a pair.

But now, if you want to access this 1. Now, if you remember well enough, I told you pair contains two guys, right? And this guy was called `first`. If you remember well enough, this guy was called `first`, and this guy was called `second`. Correct? Now, but this second guy now stores two guys. So, can I say this guy is nothing but `second.first`? You get `second.first`. So, `second.first` is what this particular guy is. And what is this guy? This is nothing but `second.second`. So, this is `second.second`. As simple as that. So, this is how you can easily access. So, if I ask you, "What is `p.first`?" It's 1. If I ask you, "What is `p.second.second`?" It's actually 4. If I ask you, "`p.second.first`?" It's actually 3. This will be the output if I write `cout`.

Okay, now what if I declare? Now, as of now, you would have been declaring arrays like `int arr[]` or `char arr[]` or something like a `string arr[]`. But can I declare a pair array? Yes, you can declare a pair array. The data type can be anything. Pair can also be a data type. Now, this is the index 0, this is the index 1, this is the index 2. Now, so you are storing pairs in your array indexes. As of now, so pair can be treated as a data type. It generally lies inside the utility library. Yes, it lies inside the utility library. Okay?

Now, if I'm trying to access `array1[1].second`, that's basically this `.second`. Of this guy, which is the second, that's 5. So, if I'm trying to print this, this is going to print 5. So, this is the entire knowledge of pair that is required in order to get started with data structures and algorithms. And the next part, we'll be learning about vectors.

So, the first container that we will be learning is `vector`. Please understand every possible function about vectors because these functions will be similar in all the other containers like `queue`, `list`, `map`, `set`. So, please, please make sure you understand all the functions in `vector` in depth. So, till now, if I ask you to store five values, the normal thing you would have done was, you would have declared an array of size five, and that will be giving you access to five possible indexes, right? If you remember well enough, this gives access to five possible indexes. The first one being 0, the second one being 1, 2, 3, 4. Now, but afterwards, if you want to modify it, like if I want that I want to enter one more element, I cannot modify the size of this array because this array has been declared of size 5, and I cannot modify the size because arrays are constant in size. So, this is where something like `vector` comes in. `vector` is a container which is dynamic in nature. Like, you can always increase the size of the `vector` whenever you wish to. So, if there is a requirement where you do not know the size of a particular data structure that will be required, that's when you think of a `vector`, and that is the best place to use `vector`.

So, `vector` is a container only, which stores elements in a similar fashion as the array does. Okay? Now, in order to declare `vector`, it's very simple. You just give the `vector` name, then you give the data type. It can be `int`, `double`, `char`, `string`, anything. And then you declare the data type name. Like, over here, it's `v`. It can be `large`, it can be `striver`, it can be `vec`, it can be `abcd`, it can be anything. Okay?

So, right after that, there's a function as `push_back`. So, if you're saying `v.push_back(1);`, what it does is, this line basically does is, it creates an empty container. Remember this. It creates an empty container. In the next line, it says `v.push_back(1);`. So, this empty container says, "Okay, I'm empty, so I'm gonna take 1 into it." So, `push_back(1)` will do this. "I'm gonna take 1 into it."

Now, there is another function as `emplace_back`. What do you mean by `emplace_back`? It's similar to `push_back`. It is similar to `push_back`. So, the moment you do `v.emplace_back(2);`, it dynamically increases its size and inserts 2 at the back. It dynamically increases its size and pushes 2 in the back. Now, generically, `emplace_back` is faster than `push_back`. You can find the reasoning why on Quora. I'll be leaving the link in the description. Okay?

Now, this is how you can define `vector`. Now, can we define `vector` of a paired data type? You can again define `vector` of a data type, as I said. So, what you just need to do is, you need to change the data type declaration inside this. So, if you just change it, you can always. But over here, there is a trick. As I said, there are a couple of ways in which you can insert elements into `vector`. One was `push_back`, the other one was `emplace_back`. So, if you're using `push_back`, you have to insert like `v.push_back({1, 2});`. You have to give the curly braces in order to enter, like, in order to insert a particular pair. But if you're using `emplace_back`, and you write without curly braces, `v.emplace_back(1, 2);`, `emplace_back` automatically assumes it to be a pair and takes it as an input and inserts into the `vector` that you have defined. So, that is how `emplace_back` is different from `push_back` in terms of syntax.

Now, what if I want to declare a container with a lot of elements already filled? So, imagine this is the size. Now, this is how you can also declare something of a size. Like, this is the size that you can give. So, what happens is `vector<int> v(5, 100);`. A container containing 100, like, two instances of 100 is already defined. It's a container containing five instances of 100 is already defined. Where this is the zeroth index, this is the first index, this is the second index, this is the third index, and this is the fourth index. So, container of size 5 is already defined with five instances of 100. What if I don't want to declare with 100? You can just declare of this. If you do `vector<int> v(5);`, what happens is a container of size 5 with five instances of 0 or any garbage value is declared. Now, this depends on the compiler. Okay? That's how you can easily do it. So, similarly, if I do something like `v1.assign(5, 20);`, this will declare a container of five instances of 20. Okay?

Now, what if I want to copy this container into some other `vector`? So, you just need to declare another `vector`, `v2`, and you need to pass on this particular `vector`, `v1`. So, `v2` will be this similar container, but a copy of it. Like, a copy of it, not the same one. It will be another container of five instances of 20. So, this is how generically the declaration is. If you know these kind of declarations, it does work. You don't need to declare any further. You might be thinking, "But Trevor, what if we define the size of the `vector` to be 5? Can we increase it afterwards?" Yes. Even after this, try this line, `v.push_back(1);`. After this line, if you try this, it increases its size and inserts 1 at the back. Yes. Even if you try this line after this, it will increase its size and expand to a size of six. So, it is allowed. Its dynamic in nature. You can always increase the size of `vector` even if you are predefining the size to be 5. Remember this.

Now, how do you access elements in a `vector`? One of the easiest ways is, imagine your `vector` is like having 20, 10, 15, 5, and 7. Imagine this is what your `vector` as of now, as the container as of now. And this is the zeroth index, as I told you, the first index, second index, third index, and fourth index. The best way to access them is, you can say `v[0]`. So, if you say similar to array, if you say `v[0]`, it means 20. This actually means 20. If you say `v[3]`, it actually means 5. So, you can actually access it in the similar fashion as you do for an array. Okay? That's how you can access it. That's one of the ways. Like, you can write directly `v[0]`, or you can write `v.at(0)`. Generally, people don't use this. So, you can just avoid it. You can simply use the stuff that you use in an array.

What's the other way? The other way is an iterator. Yes, the other way is an iterator. Now, I was telling you that through the lecture, we will be learning about containers and iterators. So, let's understand iterators. What is an iterator? Imagine the `vector`, like, let's take the same `vector` only, 20, 15, and 6, 7. Imagine this was the `vector`. Now, if I write like `vector<int>::iterator it;`. You have to write this, whatever, whatever data type you have taken `vector`, that data type, double colon, and you have to write `iterator`. And this can be anything. This can be `it`, this can be `by_t`, this can be anything. This is just a name. But the syntax is: data structure data type, double colon, `iterator`. This, and you write `v.begin()`. So, iterator basically means it points to the memory address. Because these guys would be stored somewhere in the memory, like, this 20 would have been somewhere stored in the memory, right? And that memory can have any address. The address can be 8000, 567, something, something. Remember, the address can be anything. This 10 will be right after that. This 15 will be right after that, right? So, all these possible values are actually stored in memory. So, what we do is, if we write `v.begin()`, it actually points to that memory. It points directly to the memory, not to the element. It points to the memory. Understand that. `v.begin()` means it's pointing to here, but on the memory. So, if you're trying to print `v.begin()`, you're printing the memory address, not the element. And in order to access, like, if you have read about C++, in order to access anything that is in the memory, you just write `*`. Like, if I write `*v.begin()`, understand this. `v.begin()` is going to give you the memory address. This portion. And the moment you write `*`, the element inside this is accessed.

Now, let's understand again. If I'm writing `v.begin()`, this is actually pointing to the memory where 20 is. Okay? The next time I'm doing, I'm saying, "Hey, iterator, can you just move ahead?" So, this `begin` does is, this goes here. So, now the iterator, instead of `begin`, is right at the next memory address because I have shifted the memory. And inside, all of these are contiguous memory locations. All of these are contiguous memory locations. So, if you are shifting it `++it`, it moves to the next memory. Again, if you do `++it`, moves to the next memory after that. If you're doing `*it`, what will happen? What will happen? As of now, it was 20. So, if you do `*it`, this actually prints 10 because it has shifted to 10, and now you're saying, "Star, access the value at that memory." So, you get 10. I hope that makes sense. Okay?

What if right after this, I do an `it + 2`? So, basically, I'm saying, "Shifted by two positions to this portion." Shifted directly by two positions to this portion, which has a 6. Now, if I try to print this, it will print 6. So, this is how you can easily use the iterator. Iterator is nothing but points to the memory where the element is lying. I hope that makes sense.

So, we are talking about iterators. Now, you must be thinking, "Do we have any other iterators apart from `begin`?" We do have. We have something like `end`, `reverse_end`, and `reverse_begin`. Okay? Now, imagine I have something like 10, 20, 30, 40 as the `vector`. Okay? So, this is what the `vector` is. So, if I'm saying `v.end()`, like, where does this point to? Remember this, `end` will not point to this portion. `end` will not point to this portion. Instead of that, `end` will point to somewhere right after 40, the memory location that is after 40. Now, if you on this iterator do an `it--`, then this iterator will move to 40. Then only this will move to 40. So, `end` points to a memory location that is right after the last element. Please understand this is very, very important in terms of iterator. So, you understood about `end`.

But what about something like `reverse_end` and these couple of things? These are never used. But just know it, like, it's never ever used. What is `reverse_end`? `reverse_end` basically means I am going to reverse this. I am going to reverse this. So, apparently, the reverse is 40 at first, then 30, then 20, then 10. So, now the `end` is 10. So, right after `end`, so that's this position is where it will be pointing. As this position is where it will be pointing. `reverse_end` means right after. And `reverse_begin` will be pointing to this. `reverse_begin` will be pointing to this. And there is a specific thing about this. It moves in the reverse way. Now, if I try to do `++it` on this, if I do `++it`, `it` as of now is pointing here. `++it` will move here. Yes. And after this, `++it` will move here. So, it's a reverse iterator. I have to think it in the reverse way. Like, if you just think this array in the reverse, it's 40, `vector` rather, 40, 30, 10, 20, 10. And now, if I talk about `end`, this is `end`. And if I talk about `begin`, this is `begin`. And if I say `begin++`, it moves to 30. So, it's that way. Reverse. Everything is in the reverse order. Never used. Do you need to know? Just know it for the sake of knowing. But no one is going to ask you.

We have discussed about `v[0]`, `v.at(0)`. What is `v.back()`? As the name recommends, if the `vector` is having something like this, `v.back()` means the element which is at 30 is the element which is at 30. That is the meaning of this. Now, if I'm wanting to print the `vector`, there are a couple of ways. Imagine I have 10, 20, 30 as the `vector`, and I want to print it. The simplest way is, I know the indexes are 0, 1, 2. So, I can directly loop from 0, 1, 2. Like, I can just go across and say, "Key, I'll loop from 0, 1, 2 and print it." That's a very simple way.

The other thing is, I say, "I'm going to do it iterator-wise." Because I know this guy is `begin`, so `it = v.begin()`, and I know the last guy is `end`, right after the last guy is `end`. So, I'm going to run the iterator till it does not reach the last guy. I'm going to do `++it`. The first time I get 10. Next, I move it. I get 20. Next, I move it. I get 30. And I will print every time `*it`. And this is how you can print the entire `vector`. This is how you can print the entire `vector`.

But, but, but, there is a shortcut. Now, you must not be like, "No one wants to write these long syntaxes." Because STL means short, like Standard Template Library, but it means everything in a very simpler fashion. So, STL gives you something like `auto`. So, if you write `auto it = v.begin();`, it automatically assigns it to a `vector` iterator. You don't have to say that this is a `vector` iterator. You don't need to define the data type. It automatically defines the data type. Now, even if you write `int a = 5;`, so you're defining `a` to be of integer data type. Even if you write something like `auto a = 5;`, computer automatically says that this is an integer. So, this `a` will be of integer data type. So, if you write `auto`, the data type is automatically assigned according to the data. The data type is automatically assigned. Like, if this would have been something like "Raj", `string`, and I would have written `auto a = "Raj";`, `a` would have been automatically `string`. So, `auto` means auto-assignment. So, that's that's the beauty of C++. If for some time you don't know the data type, you can just write `auto`. C++ will take care of it and it will automatically assign the data type for you.

The other way to print the `vector` is using the for-each loop. So, if I use this for-each loop, which is `for (auto const& element : v)`, so it's basically means, if the `vector` is 10, 20, and 30, I'm saying `element` first time `element` is 10. Next time `element` is 20. Next time `element` is 30. And you can simply print `element`. `auto` means on the data type, please iterate on the data type. First, iterate on the 10. Not an iterator. Not not an iterator. This means over here, `int`, because it is of integer data type. Automatically iterate 10, then 20, then 30, and automatically prints it entirely. So, that's about how to declare a `vector`, how to use it in a `vector`, how to print a `vector`.

Now, let's understand the deletion in a `vector`. So, imagine I want to delete something. So, there is something as an `erase` function. And if I have the `vector` like 10, 20, 12, 23. I say `v.begin() + 1`. Now, in order to use the `erase` function, there are a couple of things. Either you give the iterator that, "Click the location of the address. The location of the address that you want to delete. That this is the address that I want to delete. Please, please delete this address." So, I'm saying, "Okay, `v.begin() + 1`." What does this mean? `v.begin() + 1` means 20. So, if you just do `v.erase(v.begin() + 1);`, so the `vector` will be now 10, 12, 23. The `vector` will be reshuffled. The `vector` will be reshuffled into 10, 12, and 23. That is how the reshuffling will go on. So, that is one way to erase.

So, we have understood how to erase a single element. But what if I have a `vector` like 10, 20, 30, 40, and 50, and I say, "Driver, I want to delete these couple of elements. I don't want to go single." Do you have something? I say, "Yes, I have." And that's like `v.erase(start_iterator, end_iterator);`. And I say, "Give me the starting address and give me the end address after the element." Very important. End address after the element. So, starting, if I want to delete 20, can I say that's nothing but `v.begin() + 1`? I can say, because right after `begin`, that is where 20 is. I want to delete 30, that is `v.begin() + 2`. But I said, "Right after what you want to delete." So, that's `v.begin() + 3`. That's `v.begin() + 3`. 3 is pointing to here. So, I'm gonna delete this portion. But you have to give this end after the guy that you want to delete. After, right after 30, you have to give the address. So, apparently, it deletes `start` and this is something like this. `end` is not included. The `start` is included. Got it? So, please make sure you give something as which is not included, right after one, right after that. Okay? So, that's how you can easily delete it.

Okay, so for this example, we have 10, 20, 12, 23, 35. What do you mean by `v.begin() + 2`? That means 12. What do you mean by `v.begin() + 4`? `v.begin() + 2`, `v.begin() + 3`, `v.begin() + 4`. So, `v.begin() + 4` is here. So, apparently, this and this will get deleted, and you will be left out with 10, 20, and 35. I hope that makes sense.

Now, we're going to learn about the `insert` function. `insert` again. If you want to insert something, it's very simple. First of all, if you declare `vector<int> v(2, 100);`, this creates 100, like, two instances of 100 in a container. Now, if I want to insert a 300 right at the start, right at the start, so I say `v.insert(v.begin(), 300);`. So, this does is, this inserts right at the beginning. 300. Now, imagine you had like 10, 20, 30, 40. And I want to insert something here, on inside of 5 here. So, do you write? This is the first position. This is the first position. So, instead of `v.begin()`, you have to write `v.begin() + 1`. "Can you please insert 5?" So, if you write this, this 5 will go here and get inserted right at the first position. That's how you do `insert`.

Now, that was for a single element. You inserted a single element. What if I say that you have 10, 20, 30, 40 as the `vector`. I want to insert two 5s. Imagine I want to insert two 5s. How do you do that? So, you say, "I wanna insert at the first position, the number of elements that I want to insert, and the number that I want to insert." So, `v.insert(v.begin() + 1, 2, 5);`. This will do is, this will take 5 and 5 and insert it right after 10. So, this makes it 10, 5, 5, 20, 30, 40. So, if I say over here, you had `vector<int> v(2, 100);` and `v.insert(v.begin() + 1, 2, 10);`. So, `v.begin() + 1` which is right after 100, two occurrences of 10. Two occurrences of 10. Inserted. Understood? Very simple. So, that's how the `insert` function does work for this.

Now, what if you have a `vector` and you want to insert it into some other `vector`? Now, imagine I say that, "Okay, I have a `vector` like, for this example, we have `v2.assign({50, 50});`." So, I had a 50 and 50 `vector`. Okay? Now, this `vector` is named as `copy`. So, this is the line that declares that, "Okay, now I already had this `vector` 30, 10, 10, 100, 100. And now I want to insert this 50, 50 somewhere." So, at that somewhere, I give that address, and I say, "Please enter this entire `vector`." So, it will easily take this entire `vector` and enter it. If you want to have a portion of this `vector`, you can give that starting portion and you can give this after end portion, and that will also do it. Again, not required. What is required is `v.insert(v.begin(), v2.begin(), v2.end());`. This portion. This is hardly required. If you just know `erase` and `insert` about a single element, does it? Okay? That's how you can easily do about `vector`.

Now, what are the other functions in `vector`? `v.size()` will give you how many elements are there in the `vector` as of now. `v.pop_back()`: if this is the `vector`, `pop_back` pops out the last element. `v.swap(v2)`: `swap` is very simple. If this is a `vector` `v1`, this is a `vector` `v2`, it swaps the `vector` as the name recommends. `v.clear()`: doesn't matter how big your `vector` is, trims it down to an empty `vector`. Trims it down to an empty `vector`. Erases everything. Okay? And `v.empty()`: says, "Does your `vector` like, if your `vector` also has like a minimum of one element, it says not empty." Not empty. But if the `vector` has nothing, it will say `true` empty. So, these are the functions that are generically required in a `vector`.

The next container that we will be learning is `list`. A `list` is exactly similar to `vector`, but the only stuff in `list` is, it gives you front operations as well. Now, `list` is a container, again, dynamic in nature. Same way of declaration. You can `push_back` to it, you can `emplace_back` to it. So, this is the `list` that will happen if you `push_back(4);`. And after that, if you say `list.push_front(5);`, this front goes over here. 5. Like, it directly pushes it into the front. In `vector`, you have to use the `insert` operation. And if you're inserting somewhere, that does take a lot of time. Like, `insert` function in a `vector` is very costly. Like, we will read about time complexities in further data algorithmic lectures. But as of now, just remember, an `insert` in a `vector` is costlier. And a `list`, since the internal operation is a doubly linked list, like, a doubly linked list is maintained for a `list`. And for a `vector`, a singly linked list is maintained. So, thereby, something like `push_front` is very, very cheap in terms of complexity, time complexity-wise, when you compare it to a `vector`. Okay? And there is `emplace_front` as well. All of the functions, `begin`, `end`, `reverse_end`, `size`, `clear`, `empty`, all other functions are similar to `vector`. So, I will not be explaining that. Okay? So, that is about `list`.

Now, the next container that we will be talking about is `deque`. Again, similar to `list` and `vector`. You just declare it. `push_back`, `push_front`, `pop_back`, `pop_front`, `back`, `front`. And all of the functions are similar. Not going to explain this as well. It is exactly similar to `list` and `vector`.

So, the next container that we will be learning is `stack`. Now, `stack` is something as LIFO. LIFO means Last In, remember this. Last In, First Out. The guy who went in last is the guy who will come out at first. So, generally, you can just imagine a `stack` to be a data structure like this. And this is how you declare a `stack`. `stack<int> s;`. Declare the variable name like this. I'm saying `s.push(1);`. So, push 1. I'm saying `s.push(2);`. So, push 2. I'm saying `s.push(3);`. So, push 3. I'm again seeing `s.push(3);`. So, push 3. I see `s.emplace(5);`. Similar to `push`. So, I say `s.push(5);`. Now, these are the push operations. Right after that, if someone says `s.top()`. So, as I said, who's the last guy who went in? The last guy that went in, you know, is nothing but 5. So, this will print 5. This will print 5. Now, realize this, over here, indexing access is not allowed. You cannot say this is index 0, this is index 1, something like this. You cannot see in `stack`. There are only three functions: one is `push`, one is `pop`, the other one is `top`. All other there like `size`, `clear` there. But these are the generic three functions that you have to deal with. So, if I'm saying `s.top()`, it gives you 5. But the 5 is still in the `stack`. The 5 is still in the `stack`. Now, the moment I say `s.pop()`, it deletes this from the `stack`. Now, 5 is not in the `stack`. Now, if I'm saying `s.top()`, right before 5 was there, 3 said, "Print 3." Now, if I'm at this moment saying `s.size()`, there are four elements. So, I print 4. I'm saying, "Is the `stack` empty?" The answer is false. It has four elements. Now, if I'm saying `swap`, it to some other `stack`. I declare another `stack`, `s1`, and I say, "Can you please swap it?" So, `swap` is very understandable. Both, both the guys will swap. So, I hope `push` is clear. `pop` is clear. `pop` means delete. `top` means just tell me what is that top. You don't need to delete. Just tell me what is at the top. So, that is how the `stack` STL works.

Like, now talking about complexity-wise, in `stack`, all the operations are O(1) operations. Everything happens in constant time.

So, let's learn about the next container. Now, the next container that we will be learning is a `queue` data structure. Now, a `queue` data structure is similar to `stack`, but over here, it is FIFO. FIFO means First In, First Out. The guy who gets in first comes out first. `Stack` was Last In. Okay? Now, you can just think it in this way. Like, if you're forgetting names, you can say, "Like, you go into a platform, and if you're buying a ticket, what do you generally do?" The person comes in. The first person who comes and stands. And the next person who comes in and stands. So, the first guy who gets the ticket, this guy. Then this guy gets the ticket. And if someone is coming, it's a `queue` that that happens. So, that that is where the concept comes in. First In, First Out.

So, if I'm saying `q.push(1);`, I push 1. `q.push(2);`, I push 2. `q.push(4);`. So, I pushed 1, 2, and 4. And the next line, I'm saying `q.back() += 5;`. But `back` will mean 4. It does not mean this guy. `back` will mean 4 only. So, over here, I'm saying `4 + 5`, this makes it 9. I'm not saying `q.back()`. So, if I'm saying `q.back()`, it prints the last guy, 9. I'm saying `q.front()`, prints 1. Just prints, does not deletes. If I'm saying `q.pop()`, deletes. Deletes, deletes, deletes the front guy. First 10 guy. `q.front()` is now 2. So, it prints 2. It is similar. And now, all the operations are much more similar to `stack`. `size`, and all these things. That's how `queue` works. Again, all the operations are happening in constant time.

The next thing that we will learn is `priority_queue`. Now, as the name recommends, priority. The guy who has the largest value stays at the top. It's similar to `queue`, but there is something that happens inside which you'll learn probably after a couple of years when you are appearing for interviews. But as of now, just understand the logic. Okay? So, remember, if you're declaring `priority_queue` like this, the maximum element stays at the top. Or the largest element. If you're using character, the largest character. If you're using integer, the largest integer. If you're using string, the lexicographically largest string will stay at the top. Okay?

So, I'm saying `pq.push(5);`. So, you push in 5. I say `pq.push(2);`. So, you push in 2. I say `pq.push(8);`. So, you push in 8. Now, I say `pq.push(10);`. Okay? Now, the moment I say `cout << pq.top();`. Of all these elements, which one is the largest? 10. So, it prints 10. And that is the guy who will be at the top. Now, if you are trying to insert something like 3, 3. The 3 will go right here. The 3 will go right here. And this is not a linear data structure. Inside of it, a tree data structure is maintained, which you learn in the later half. Now, understand one thing. The data is not stored in a linear fashion. Like, inside, at inside, a tree is maintained, which you learn someday. Okay? So, as of now, if I say `pq.pop()`, the topmost element is popped. 10 is popped. If I say again, `pq.top()`. Is the topmost 8? Yes. So, this is how the `priority_queue` works. Again, `push`, `top`, and `pop` main functions. The other ones are `size` and `empty`. `size` and `empty` is very simple. And `swap` is also very simple. So, these are the functions.

What if I want a `priority_queue` which stores the minimum element at the top? Then this is how the syntax is: `priority_queue<int, vector<int>, greater<int>> pq;`. And if you give this data type, and now if you push 5, 5 is there. If you push 2, 2 is there. If you push 8, 8 is there. If you push 10, 10 is there. But this time, if you try to access `pq.top()`, 2 will come out. So, that's how you maintain a very simple minimum `priority_queue`. And generally, it's known as min-heap. And this is known as max-heap. Remember these terms that you learn in DS Algo as you move forward.

What is the time complexity of `push`? `push` happens in O(log n). `top` happens in O(1). And the `pop`, which is the deletion, again happens in O(log n). So, this is how it happens. If you don't know what is logarithmic of n, no issues. Just keep this in your mind. As you move forward, you will understand in DS Algo.

Now, the next container is very, very interesting. And that is nothing but the `set` container. Now, what is `set`? Just remember one thing. It stores everything in the sorted order and stores unique. Just remember these couple of points, and you know what is a `set`. Everything in the sorted, and just unique. Just two points, and you're done.

Let's understand. So, imagine this is the container. And I say `s.insert(1);`. So, you insert 1. Imagine you say `s.emplace(2);`. So, you insert 2. Imagine you say `s.insert(2);`. Unique? So, will it store 2 again? No, it does not. No, it does not. It does not store 2. If I say `s.insert(4);`, will it? Yes. If I say `s.insert(3);`, it will. But it will insert it here. Again, a very important thing. Sorted. Stores in a sorted order. At first, it will have 1, then it will have 2, then it will have 3, then it will have 4. Everything in the sorted fashion. So, it stores everything in the sorted fashion. So, this is how the `set` will be storing. Again, a container. Is it a linear container? No. A tree is maintained. So, I'm just explaining you via this bucket. But inside of this, there is an entire tree which is maintained. Again, which you learn as you move forward. So, `insert` and `emplace` works in a similar fashion. Sorted and unique.

Now, there are functions. If I say `s.find(3);`. And this is the `set`. So, it will return an iterator. Remember this. Returns an iterator which points to this 3. Which points to this 3. It returns an iterator which points to this 3. Okay? So, basically, this is an iterator. Remember, iterator points to the address. Perfect. Now, if I say `s.find(6);`. Is 6 here? No. If an element is not in the `set`, please hear me out properly. If an element is not here in the `set`, it will always return `s.end()`. That means an iterator which points to right after the end. Imagine the `set` is having 1, 2, 4, 5. And you did `s.find(3);`. And you don't have a 3. So, you will have an iterator `end`. This is the iterator which points after 5. After 5. That's where `find` will turn the iterator to be. It points afterwards. Okay?

And after this, there is `s.erase()`. It's very simple. Erases this guy, 5. It erases this guy, 5, out of it. Like, if this is the `set`, if this is a `set`, it will delete 5. It'll simply delete 5. You don't have to think anything. Deletes 5 and maintains the sorted order. Deletes 5 and maintains the sorted order. Now, as I said, `set` is nothing but unique and sorted. So, if you're trying to count if it exists, if it exists, it will only have one occurrence because it does contain unique. And if it does not exist, it will have zero. So, if 1 is there in the `set`, it will give you 1, like, one occurrence. If it is not, it will give you zero. As simple as that. Okay? You can also erase. Like, you can either give the element to be erased. Like, you can give the element to be erased, or you can give that, "Okay, this is the address or the iterator. Please go and erase this iterator." As simple as that.

Now, in `vector`, we did learn about `erase(start_iterator, end_iterator)`. Similar thing also works over here. If you want to erase everything. Yes. If you want to erase everything between 2 and 4. Imagine you had something like this. So, 2 is here, 4 is here. If you get the first guy, if you get the second guy. So, if you do `find`, you'll get the 2 iterator. If you do `find`, you'll get the 4 iterator. So, if you do `s.erase(s.find(2), s.find(4));`.

get the force iterator so it deletes two and three. remember this. it deletes two and three, not four. four is this bracket and this is this. please remember this.

now in set, there are other functions like size, empty, swap. everything is similar to vector. that is, begin. all of these are similar to vector, so I will not be explaining them. the most important are find, count, and insert. these are the most important ones. and as well as it is now, they have something as a lower bound and an upper bound. so I will be linking a video in the description which explains lower bound in depth and upper bound in depth. so please go back and watch lower bound and upper bound. once you have seen that, you will actually understand how does this low bound and upper bound work in a set. it's the exact same that will be taught in the video which is in the description. so please make sure you watch it.

now in set, everything happens in logarithmic time complexity. if you're inserting, it takes logarithmic. if you're erasing, it takes logarithmic. everything happens in a logarithmic time complexity. again, if you don't know log in, no issues. please remember this in your head.

now we did learn about set and I said sorted and unique. that means it will just contain one occurrence of two. you can insert thousands of occurrences of two, but it will just store one occurrence of two. but there is something as multiset. if you define multi set, it only obeys sorted and will not over unique. it will store multiple occurrences. like if you try to insert one, one, one, stores all the occurrences. and you try to erase one, but all the occurrences are erased this time. but if you do an it is one, it erases every one. and this time count will count you the number of ones in the multi set. but if you want to delete, imagine your multiset is containing three ones, and I just want to delete one occurrence of one, or two occurrences of one, or three occurrences of one. so what I can do is, I can just find out the first occurrence of one. so I'll just do multi set dot find because I know find points to the iterator and also erase that iterator instead of saying it is element. because if I say understand, if I say erase element, it erases all the elements. but if I say it is address, it only erases that portion. it only raises that portion. and I don't know it is like two two ones. so I say it find one and go till two. go till two. so it really raise both of them. both of them. so either it is element, it is address, or it is starting address and right after the end. that's it. diet raters and rest all functions are same as set. stores everything in the sorted, but not unique. stores multiple occurrences. like one, one, one, two, three, three, four. it can store multiple occurrences as well. so that is the definition of multi-set.

now we did learn about set. we did learn about multi-set. now there is something as unordered set. everything is similar to set. the only thing that is omitted, like it stores unique. the only thing on it is it does not stores in the sorted order. we don't know how it will store. it has randomized order. it has randomized order. like if I put in one, after that I put in five, after that I put in two, after that I put in three, after that I put in six. it can have this order. it can have any order in the world. but it will just have unique elements. like if I try to insert one again, it will say I have one. I have one. and in most of the cases, the time complexity is b go of one. everything, like all the operations are same. insert, erase, all the operations are same. but only the lower bound and upper bound function does not work. all the operations work, but the lower bound and the upper bound functions do not work. remember this. all operations are similar to set, and they do not store everything in sorted order. so all the operations are generically in a big o of one constant time. but in the worst case, which happens once in a millennium, like if the data is through, like possibly given in such a way that they want you to explore the worst case, which does not happen, then the unordered set goes for a we go off and linear time. it goes for the worst case. again, does not happens every day. happens once in a blue moon. the time complexity goes till we go off and you just write them down in notes. you will understand these things when you move across or when you grow in experience. that's how the unordered site works.

so the next container that we will be learning is a map container. okay. now you can think this as something like, just take a task. when I say, in your college, there will be like, there might be multiple people with raj name, but how do you distinguish themselves by roll numbers, right? one raj might have a roll number of 23. the other raj might have a roll number of 25. the other raj might have of 28. so you know this one guy is of roll number 23. the other guy is the roll number 25. the other guy is of roll number 28. so generally, this is uh, in in your class, this is store like this. roll number one, roll number two, roll number three, and so on. if there are 50 people, you store it like this. so map, you can think this as a as a data structure or a container which says the roll number is my key, and over here, the value can be the name. so this is what the data structure means. you store unique keys because you can't have 23 rule number twice. you can have it just once. so the keys are unique. the keys are unique, but the values can be like, over here, there can be a raj. over here, there can be a rod. so there is one guy with key three who is raj. there is one guy with key 50 who is raj. there can be duplicate values, but it has to be a unique key. so you can think map as a container which stores everything in respect of key and values. and very important thing, this key can be of any data structure. it can be integer, sorry, any data type. it can be integer, it can be double, it can be pair, it can be anything. similarly, this value can be anything. so how do you define map? this is key, this is value. he is integer, value is integer. over here, he is an integer and they're saying value is two integers. over here, they're saying key is two integers and value is one integer. so you can define it as you wish to. that is on you. this is how you define. okay.

now if I'm defining the map to be this, for an example, assume you're defining the map to be this. now I say one equal to two. it means on the key one, can you please store two? so this is what it stores internally in the map. internally in the map, it stores one comma two. next, I say I don't want to store it like this and place three one. so it stores three is the key and the value to three is one. it does a similar thing. stores it into the map. again, I say insert. you can also use insert two comma four. goes and stores two comma four. and this is how you can store all these three variables. okay. so in this way, you can actually store for this particular declaration. and remember one thing, map stores unique keys. very, very important. map stores unique keys in sorted order. something similar to set data structure. map stores unique keys in sorted order. something similar to set data structure. okay.

now this is the declaration. the second declaration for this declaration, sorry, or this declaration. this is the key. so you have declared the key like this, and the value is a single integer. so this is it for this. it will be storing like, okay, key is 2 comma 3. so this is stored. and the value corresponding value is 10. perfect. so this can be stored like this. that's how it generically stores. okay. I hope that makes a lot of sense. I told you that everything is stored in a sorted order. so this will at first store 1 comma 2, then it will store 2 comma 4, then it will store 3 comma 1. this three lines will be storing like this. so again, if you want to explore or if you want to iterate on the map, one of the ways is you start from beginner iterator and you go until end iterator. similar in the vector. all you do is you say i t. you run a for each loop. first time id is here, so it stores in a pair. next time id is here, stores in a pair. next time id is here, it stores in a pair. if it is storing in a pair, this is id.first and this is id.second. so first time prints one two. next time goes here, prints to four. next time goes here, prints three one. so we try to do this c out. this is how you can actually traverse in a map. and everything is stored in a sorted order of key. in a sorted order of key, not value. sorted order of key. remember this. sorted key is how it stores. no duplicates. all uniques. okay.

now if I want to access map of one, if I want to access map of one, it says a value two. it says a value two because at one you're storing to. but if it tries to access five, will it find five there? there is no five. so what happens? it it says null. but if you want to print it, it actually goes on prints zero or null. okay, because it does not exist. so if something does not exist, it gives you zero. okay. so this is how you can easily access for a key. now if you wanna know the iterator, imagine you want to know where the key 2 lies, the address of it. so again, the find function will come over here and say map.find3. so this is where you get it. diet rater. in order to access this, you give a star. so this access is this, and we want the value. dot second. got it? it gives you the iterator to the this three comma one. okay. this id is this. so if you give a star, it's the element. and if you give a second, it has the one. that's how you can easily access this as well. now over here, if you try to do dot find five and five is not there, it points to nothing. but dot end. and end means after the map. after the map. okay. make sense. and again, the lower bound and upper bound functions. if you have seen the video in the description, you can understand how lower bound and upper bound works. okay. and all the other functions like it is swap, size, empty are same. so I'm not going to explain it again.

next thing is multi-map. similar to map. only thing is you can store duplicate keys. you can store duplicate keys. something similar to set and multi set, as I told you, right? duplicate keys, but everything in the sorted order. this time you can store like one comma two, and then you can come across and again store like one comma three, right? so you can store duplicate keys over here.

unordered map. again, unordered map is similar. only this portion will go across. it will not store in sorted. it will be randomized. it will be randomized. but it will it will not have duplicate as well. it will just have unique keys. unordered map will have unique keys, but it will not be sorted. and the difference is like, the map works in logarithmic of time, and the unordered map in the in almost all cases works in constant time. in the worst case, it goes for big offen. again, this worst case happens once in a blue moon, not always. in almost all the cases, we go of one is what appears. so as of now, I can say that I have completed containers and iterators.

now this is not required. not required. no need to learn it. just omit this. now I'll be telling you the all the important algorithms like which are mandatory, like you should know. and all the other algorithms which I will not teach, you will eventually learn while you code, but that are not like those are not important. so as of now, you can just leave it. eventually, with time, if it's required, learn at that moment. no need to learn it now. so let's move across to learn some algorithms.

now if I say you that, hey, listen, I give you an array of size like one, five, three, or two, okay, of size four, and I want you to sort it. so you will be like, let's apply bubble sort, merge sort, selection sort, so and so. but in C++ STL, if you just write the line sort a comma, it's a four size. so this actually means the first position, the first position of the first iterator, the starting iterator, and this means the last iterator. a plus four actually means this portion, then portion, the last iterator. again, similar to something like start, start is included, and end is not included. so you write the starting iterator, which is a, which actually points to this, and a plus four, which actually points to this. so all the elements are sorted. right after this line, it will have one, two, three, five. so you don't have to actually use merge sort, bubble sort, selection sort. it sorts that into one line. and if you're using vector, the starting is begin, this is the ending, the starting iterator, and the ending iterator. so in this way, you can sort any container, not map. all, like all, not map. I'm talking about vectors and arrays over here. okay.

now what if I just wanted like, I had something like one, three, two, five, and rather let's keep it like five, two. okay. and I wanted just this portion to be sorted. so I know a plus two, because this is a plus two for sure. I know a plus four. right after this is a plus four. so only this portion will be sorted. so this is how only this portion will be sorted. perfect.

what if I want to sort them in descending order? imagine you have like one, three, five, and two. I want to sort them in descending order. so it's very simple. give the starting iterator, give the ending iterator, the portion that you want to sort, and just write greater end. yes, just right greater end. and this is nothing but a comparator. an inbuilt comparator which automatically sorts it like, I'll teach you comparator. automatically will sort it in the descending order. like this, in a descending order. you just need to write greater end, and it automatically sorts it into a descending order.

now what if I want to sort it in some other fashion? because as of now, we know how to sort it in increasing. we know how to sort it in decreasing. but what if I want to sort it in my my way? because going across, you will see that this my way is being used a lot. for an example, we have declared a pair array, and these are the pairs: one, two; two, one; four, one. okay. and I want you to sort according to the second element. like I want you to sort it in in order of increasing second element. please understand, I want to sort it according to increasing second element. okay. and if the second element is same, then sort according to the first element, but in decreasing. but in decreasing. what do I mean by that? so as of now, can I say the second element is 2, 1, and 1? so these 2 comma 1 and 4 comma 1 are the guys who should appear right at the first, okay, because the second elements are one and one. and after that, I can say, after that, one comma two will appear because because of this portion. so can I say that I've sorted according to the second element? but I still have a problem. now these couple of guys are having the same second element. now if they have the same second element, I want you to sort it according to the first element, but in descending, which means I want you to have 4 comma 1 at first, and then 2 comma 1. that means among them, among them, I wanted to sort it according to descending. so first 4, then 2. and then you can write. so first sorted according to the second, and if there is a group which is having the same second, then among them sorted according to the first. so this is my way. this is my way. okay. it's it's something like a combination of increasing as well as decreasing. so this is where generically you write the first iterator, the last iterator, and a comp and a comp parameters and a comp. now this is nothing but a self-written comparator. a self-written comparator. and this comparator is nothing but a boolean function. is nothing but a boolean function. so I've written this, but I'll just teach you how to write it. it's very simple. you write boolean comparator, and this is the function. okay. this has to return a true and a false. this has to return a true and a false. now go back and see what is the data type that you that you just had, and the data type, if you see, was pair of int. just copy paste and have couple of guys. pair one and pair two. that's it. have couple of guys. this is the first thing that you'll do. have couple of guys. now please understand this, that this is player one and this is pair two. so forget about the array. forget about the array. and now think of these two instances where you have two pairs, where you have two pairs. this is p1, this is p2. while writing comparator, just focus. what have you been said? sorted according to the second element. so you say, okay, okay, if my p1.second is already smaller than second, that means it's true. we are assuming, we are assuming that the pair one lies before p2. lies before p2. that is what the assumption is. the pair one lies before p2. and that is okay. if the second guy is lesser than the second guy, I'm okay. they should actually, so they are in the correct order. this competitor says, are two guys in the correct order or not? and I'm saying they are in the correct order. they are in the correct order because this guy is smaller than this guy. and that is what I was said. so if they are, they are in the correct order. but but I know one thing, if it's the opposite, if this is the case, I will say they are not in the correct order. because if I have two guys, okay, and imagine this is five and this is four, and I'm saying p1 occurs before p2. this is wrong. this is wrong. if this second is actually greater than this, I know this is wrong. so I say they are not in the correct order. so what happens is comparator internally says p1 and p2 are not in the correct order. can you please swap them? so apparently four comes before five. this is what happens. so they do internal comparisons and they swap. so I told them false. they are not. so they will swap internally. but do we have any other conditions? we have what if they are same? because that's the only condition that is left. that is the only condition. because if if these two conditions do not happen, I know we will come to a point that they are same. I don't need to write if, because that's the only condition that is left. they are same. now if they are same, will again try to evaluate. I know if they are same, this is p 1 and this is p 2. and this time it is descending. so this guy is greater than this guy. it's okay. otherwise, it's not. so can I say if p1.first is actually greater than p2.first, it's okay because this is what I was looking for. else, I say it's not. if they're equal, it's fine. I I even if I swap or do not swap, it's okay. so can I say if it's greater, it's okay? that's what I'm looking for. whatever it's not, that's false. please swap it. if it's not, I need in descending. can you please just swap it? so you just analyze everything. whenever you try to write a comparator, always analyze everything in terms of two pairs. don't think in terms of arrays. just pick up. yes, I repeat. you just need to do one thing. just pick up one pair. just take another pair and try to analyze p1 and p2. that is your job. so you have learned about comparators. so anytime there is my way, my way sorting, you can write the comparators. just need to write this and you should be done. just focus on the data type and try to just have evaluate two data types and write it. nothing different. okay.

so this is again one more STL which is very important, which is built in popcorn. so if number seven, what is the binary of seven? it's one one one. that's the binary of seven. so there's a built in popcorn. it says, okay, this has three bits as one. typically, number seven means zero zero zero zero zero zero. like these are the 32 bits inside the computer. in 32 bits, it's zero zero zero zero zero zero and one one one. so built in popcorn says, how many ones are there or how many set bits are there? so it will return three set bits. if this number would have been six, which is nothing but one one zero. six is nothing but one one zero. so built in popcorn would have returned two. the number of set bits. okay. if the number is long long, then built in popcorn becomes built in popcorn ll. built in popcorn ll. if the number is long long integer, will not suffice that. perfect.

now the last thing is, not the last, second last thing is next permutation. now if I write a string as one, two, three, and I want to have all the permutations of it, all the permutations. so what I can say is, okay, listen, I'm gonna have the string. and I know, I know the next permutation is one, three, two. I know the next permutation. like if I talk about dictionary order, two, one, three. the next permutation is two, three, one. the next is three, one, two. the next is three, two, one. can I say these are the dictionary? like these are the six permutations that you can have. three factorial is six. so if you want to print them, what you do is, you first print the first string, then you say, can you have the next permutation please? and you have the next permutation. and it takes you the string which was this becomes one, three, two. and now you print it. again, the string now becomes two, one, three. and you print it. again, the string becomes two, three, one. you print it. again, the string becomes three, one, two. and you print it. again, the string becomes three, two, one. and you printed. right after this, it goes to null. it says no more permutations. it returns a false. if there are no more permutations, it returns a false. and if it returns a false, the while loop breaks. and this is how you can print all permutations of a string. here's a catch. what if the string was 231? then it would have started from 231. an x permutation of 231 is 312. and the next is 321. so it would have just printed like first tense, then this, then this. right after this, no permutations. so it's very important that if you want to print all the permutations, you start from the sorted guy. like you just start from the sorted guy. and you can easily sort it. you know the STL. now in this fashion, you start from the sorted guy. and that's how you can easily print it.

now the last one is max element. imagine you have an array like one, n, five, six, and even the maximum element. so if you give max element star iterator and iterator, it gives you the address. and if you give the star, it gives you the element. similarly, min element is also there, right? so these are the algorithms that are generically used in DS algo in your day-to-day life. all the other algorithms are there, but they are not widely used. and you will not be requiring them. so whatever STL I've taught in this video is more than enough to get started with C++. so just in case you've understood everything, it's an honest request that get into the comment section and just write one line comment. because that is the only thing that keeps you motivated to make these kind of content. and if you're probably the first time on this channel, please do consider subscribing because I have a lot of content regarding trees, graphs, dynamic programming, DSA that might help you in your longer run. so please make sure you subscribe to this channel as well. and you can like this video. and yeah, please, please do comment because that keeps me going. with this, I'll be wrapping up this video. let's meet in some other video. till then, bye, take care.

[Music] don't ever forget.