Learn Data Structures and Algorithms Visually – Crash Course

#Data Structures #Algorithms #Arrays #Linked Lists #Stacks and Queues #Hash Tables #Trees #Graphs #Searching Algorithms #Sorting Algorithms #Recursion #Backtracking #Greedy Approach #Divide and Conquer #Dynamic Programming #Programming
💬 Chat with this Video
Ask anything about this video…
Data structures and algorithms don't have to feel like an intimidating wall of complex jargon and syntax. In this comprehensive crash course, Sue meets Shaha will teach you foundational computer science concepts using relatable real world analogies without writing a single line of code. You will develop a clear intuitive mental model of how data is stored, searched, and optimized. Once you master the underlying logic and problem solving mechanics here, implementing them in any programming language becomes easy. >> All right, let me start with a very simple question. Think a little before you answer. Has this ever happened to you? You are holding a long grocery list for the month and searching for the most expensive item. Or say while scrolling through your contact list, you suddenly see that a friend's number was saved twice by mistake. It also happens that you woke up in the morning and make a to-do list for the day. As you finish your tasks, you cross them off one by one with satisfaction. Suddenly, an urgent task pops up and you place it right at the top of the list. If you have done even one of these things in your life, let me tell you a secret. You have already practiced data structures and algorithms. Yes, without realizing it, you have thought like a programmer, organized data, and used a specific path or algorithm to solve those problems. The only difference is that you didn't know these have fancy complicated names in computer science textbooks. The real trouble starts with our fear. Whenever we hear these complicated names in books or tutorials like arrays, link lists, pig notation, time complexity or recussion, an invisible wall instantly goes up in our minds. Suddenly, it feels like, "Oh boy, this must be some incredibly difficult math stuff. No one but a rocket scientist could possibly understand this. It seems like it has nothing to do with our common daily thoughts. But do you know the truth? We are constantly using these things every day in our heads, at our desks, in the kitchen or in the smartphone in our pockets. Today we are going to break that very fear. We will bridge the massive gap that has formed between our everyday familiar experiences and these difficult computer science terms. Today we'll dive deep into data structures and algorithms. But it won't be like those monotonous boring classroom lectures at all. We'll proceed like a beautifully organized story where everything is interconnected. We'll look for the story behind why we move from one topic to another. You'll see that nothing feels disconnected or like something you have to memorize without understanding. And you know what the fun part is? Throughout this entire journey, we won't write a single line of code on the screen. You know why? Because the AI will write the code, right? But you'll realize by watching this full video that data structures and algorithms can be learned even without writing code. Not only that, but this is actually the best way to learn it because we'll try to understand the mechanics behind it. Our main goal will be to understand what these things do behind the scenes, why they do it, and which one comes in handy when we face a problem. Once you grasp the actual logic behind something, translating it into code in any programming language, be it C++, Java, Python or JavaScript, is simply a matter of time. Once these concepts become clear, a fantastic mind map of the entire subject will be drawn inside your head. Then you will see that you can effortlessly tell yourself exactly which data structure will work like magic to solve a particular problem. As soon as you step into the world of programming, you hear a term data structure. But have we ever asked ourselves why we need to organize data in such specific ways? Data is just data, isn't it? No matter how we leave it in our system, we should be able to find it when we need it. Then why all these unnecessary rules, complicated names, and such complexity? To find the answer to this question, let's take a look at the desk in our study room. Close your eyes and think for a moment. On your desk, all your notes, exam papers, electricity bills, and bank statements from the last 5 years are piled up in a huge disorganized heap. A literal mountain of paper has gathered on the table. Suddenly, your father comes and asks you to find the electricity bill from March 3 years ago. He really needs it. Now, think what will your situation be? How long will it take you to find that one specific paper by digging through that huge mountain of messy papers? Maybe hours will pass and the whole room will be a mess. You'll be completely drenched in sweat. It could even happen that after searching everywhere and turning the world upside down, you still won't find the paper. Let's change this scene a little bit. Suppose there is no mountain of messy paper on your table. Instead, there is a very nice file cabinet kept there. The cabinet has separate drawers for each year. For example, 2022, 2023, 24 and so on. Also, inside each drawer, there are separate folders neatly organized by month for instance January, February, March. Now, if your father comes and asks for that specific electricity bill, what will you do? You will go straight to opening the 2023 dryer. You will take out the march folder from there and in the blink of an eye within just a few seconds hand the correct paper to your father. If you look closely you will see that the core elements or data between the first and second scenes haven't changed even a bit. The papers are exactly as they were before. The information inside the papers is exactly the same. Only one thing created the difference. How the papers were organized. And just because of this difference in organizational method, hours of backbreaking labor turned into a simple task taking only a few seconds. Our work speed increased a thousand times. This is exactly the core philosophy and real power of data structures. When we work with thousands, millions or billions of data points in computer memory, if we leave them scattered randomly, the computer will struggle immensely to find the data. Our software or app will slow down, hang or simply crash. Data structure means organizing data inside memory in such a smart and tidy way that it becomes very easy to work with the data later on. For example, finding something quickly, adding new data or deleting unnecessary data. This task should be done extremely fast and at a much lower cost. There is a very important point here that we need to fix firmly in our minds which will be helpful to us at every step ahead. When we perform a task, the calculation of how much time and memory the computer consumes to do it is what we call efficiency. We do not need to get into the nitty-gritty of heavy mathematics or complex equations. Just remember this simple truth. If you organize the same data in different ways, the speed of your program will also be completely different. This one line will remain the key to our entire journey ahead. From this urge to organize data, the oldest and the most fundamental data structure of programming was born named array programming. We have all been more or less introduced to it during our early days of learning. Let's try to understand how it actually works internally using an example from our familiar world. Surely you have the experience of watching a movie in a cinema hall. At the entrance, we look at the ticket in our hand which might say row A seat number five. What are the hall seats like? placed right next to each other arranged in a straight line. Set number two is right next to seat number one and right beside it is number three. It continues in this way. Now think about it. When you enter the hall, do you go to the person sitting in seat one and ask brother where is seat number five? Then do you ask the same question to someone in seat two? Not at all. You know very well that seats are arranged sequentially and each one has a specific number. Without anyone's help, you can confidently walk straight to sit number five and sit down. The time it took you to sit in seat number five is exactly the same amount of time it would have taken to sit in sit number one or 10. In computer memory, this array works just like the seats in a cinema hall. When we create an array in memory, the computer like a very obedient child allocates blocks or spaces for us right next to each other in memory. There are no gaps in between and a specific serial number is assigned to each of these places. In programming language, we call this number an index. However, there is an interesting aspect here. Even though our general calculations start from one, the computer serial numbers start from zero. For some reason, computers seem to really like the number zero. The greatest magical power of an array is its instant access, which means the ability to reach data in the blink of an eye. Suppose your IRA has 10 million data points. You command the computer, bring me the data at the 5 millionth index. The computer will not search even a little bit. In a split second, it will go directly to that 5 millionth spot and hand you the data. In technical terms, this is called constant time complexity. Simply put, no matter how large the mountain of data is, if the specific index is known, the time to find it will always be the same. And that time is very close to zero. But as the saying goes, nothing in this world is perfect. This is true to the letter for arrays as well. Behind this incredible strength lies a huge weakness. Let's go back to that movie theater again. Suppose people are packed tightly in seats 1 through 10 in a row watching a movie intently. Suddenly the hall manager announces that for a VIP guest, a new seat must be placed exactly between seats three and four. Now imagine what a huge problem this is. There isn't even an inch of space in between. To insert a new seat there, the poor person in seat four will have to get up and move to five. The person at five will have to move to six. The person at six to seven. This way, everyone all the way to the end will have to leave their spot and shift one seat to the right. This will create extreme chaos and annoyance among all the people in the hall. Right? and a lot of time will be wasted doing this whole task. The exact same thing happens inside an array. When you try to insert new data into the middle of an array or want to delete data from the middle, the computer is forced to move all the following data one spot forward or backward. We call this shifting. Now, if the amount of data is small, it might not be a big deal. But if there are hundreds of thousands or millions of data points, then this task of inserting or deleting data in the middle becomes a massive time consuming and annoying job for the computer. So what is the solution? We want speed, but we don't want to deal with this hassle of inserting data in the middle. We need a solution where we can easily add new things whenever we want, wherever we want. And that too without bothering anyone. It is from this deep human desire that our next data structure is born. Its name is link list. To avoid the hassle of shifting seats and the pain of finding data in between, computer scientists came up with a brilliant idea. They said there is no need to keep the data packed tightly or side by side memory. Let them sit anywhere in the free memory space as they please. We will just provide a link of communication between them. This wonderful concept is called a link list. To understand this link list concept easily, we can think of a treasure hunt game. Many of you might have played this game in your childhood. What actually happens in the game? When you start the game, you don't have the entire treasure map or the addresses of all the locations in your hand. You only have a small note in your hand with the first clue or hint written on it. That note might say, "The next note can be found under that big mango tree in the garden." You run towards the mango tree and find the second note there. It says the next clue is hidden by the old well. This is how one note points you to the address of the very next note and you passing through one address at a time eventually find the treasure box at the very end. A link list works exactly by the rules of this treasure hunt game. Here we call each piece of data a note. Each note contains two things. Firstly, our actual data such as a number or a name and secondly the address or pointer to where the next node is sitting in the memory. In simple terms, the first data tells you where the second data is and the second one tells you the location of the third. Even though they are scattered here and there in the vast kingdom of memory, they remain strung together like a thread through this chain of addresses. Now think about it. How does the link list magically disappear at the hassle of inserting data in the middle like in an array? Suppose in our treasure hunt we want to add a new note or clue right between the second and third notes. Do you have to move the mango tree or the old well in the garden even an inch for this? Not at all. We just erase the address written on the second note and write the address of the new note there. And in the new note, we write the address of the third note. That's it. The work is done. Not a single piece of data in the memory had to be moved. Therefore, adding or deleting anything in the middle of a link list is extremely easy and very fast. But wait a minute. When we were talking about arrays, we said that there is nothing perfect in the world of programming. Everything is a tradeoff. Meaning to get something, you have to give something up. The link list did indeed give us the advantage of inserting data very easily. But in return, it took one thing away from us. This is the ability to reach any data in the blink of an eye. Just think, in a treasure hunt game, can you jump straight to the fifth note at the beginning? Never. No one knows where the fifth note is, except for the fourth note. And again, only the third note knows the address of the fourth one. So, you are forced to always start from the first note and work through them one by one to reach the fifth. In a link list, if you want to see the 100,000th piece of data, you have to start from the first one and cross 99,999 pieces of data before getting there. In terms of searching, it is therefore quite slow. This link list also has some interesting and useful types that we need to know about. First, let's talk about the singly link list. What we are discussing all this time is actually a singly link list. Its main characteristics is that it can only move forward. Each node only knows the address of the next node. It has no information about where the previous one is. It's a lot like a one-way street. Cars will only run in one direction. Now imagine you have moved forward in a treasure hunt game, but suddenly you feel the need to read the previous note again. In a singly link list, you cannot go back. You have to start all over again from the very beginning. To solve this hassle, the doubly link list was introduced. Here, each node doesn't just keep the address of the next data. It also carefully keeps the address of the data immediately preceding it. Meaning, this is a two-way street. If you want, you can go forward and you can also walk backward whenever you please. And the third type is the circular link list. Now, imagine the very last node in our list keeps the address of the very first node at its next address. What would happen then? The entire list would join up like a round wheel. It would have no beginning or end. You would just keep going around. Do you know where this is used? When you listen to music on your phone's player with loop or repeat mode on, you will notice that as soon as the last song ends, the first song starts playing again on its own. The concept of the circular link list is what works behind this magical task. So, what is the bottom line? Aries give us the power to find data quickly, but they get exhausted when it comes to adding or removing data. On the other hand, link lists give us the freedom to add or remove data in the blink of an eye. But to search for data, it has to work a long way. This is the true expertise of a good programmer. Choosing exactly which one is needed for which task. If you treat every problem with the same simple solution here, you are doomed. Does your app need to search for data repeatedly? then choose an array. Or does your app need to add new data in the middle frequently? Then go for the link list. This subtle knowledge of the difference will turn you from a regular coder into an expert software engineer. So far we have seen how to organize data in memory. Sometimes sidebyside like an array and other times scattered around and linked like a link list. But in real life we encounter situations where more than where the data is the important thing is the order in which the data enters and leaves. Based on this rule, two amazing data structures have been created named stack and Q. Let's start by talking about the stack. The simple meaning of the word stack is a pile or heap. To understand this, imagine a familiar scene in your dining table or kitchen at home. Suppose many dishes have been washed at home and now need to be organized. You place the first plate on the table. You place the second one right on top of the first, the third one on top of the second. In this way, a high pile of 10 plates is formed by placing one on top of another. Now, when you need a plate to eat, which plate will you pull out first? Would you try to pull out the first plate from the very bottom? Are you crazy? If you try to pull the bottom one, the whole pile will come crashing down. Naturally, you will pick up the plate from the very top. Meaning, the plate you place last is the one you are picking up first. The simple and natural rule of our daily lives is known in computer science terminology as lio or last in first out. This means the data that enters the system last will be the first one to come out. And the data structure that follows this rule to the letter is what we affectionately call a stack. There are mainly two operations that happen within this stack. When we add new data to the very top of the stack, that action is called push. Just like placing a new plate on the pile of plates. And when we remove or delete the data from the very top, that is called popping. Just like picking up the top plate to use for a meal. To be honest, we are using this stack every moment of every day on our computers or smartphones. We don't even realize it. For instance, when you browse the internet, suppose you go to Google first. From there, you click a link and enter Facebook. Then clicking another link takes you straight to YouTube. Behind the scenes, your web browser is arranging these pages in an invisible stack one after another, meaning it is pushing them. Now, if you click the browser's back button, do you go straight to Google? No, you go back to Facebook. This means the page you were on last is the one returning or popping first. Only by pressing back again do you reach Google. This is a living example of the stack in action. Again, suppose you are watching something in Microsoft Word or editing a photo in Photoshop. Whenever we make a mistake, we quickly press Ctrl Z on the keyboard to undo it. Right? Every time you type a new word or make a stroke on an image, the software quietly pushes those actions into a stack. Whenever you press undo, it pops the action at the very top of the stack which is the last thing you did and your document returns to its previous state. Don't be surprised in programming when a function is called memory uses a call stack in the exact same way. Now let's talk about cues. By now we have understood the stack rule. Whoever comes last lives first. But does this rule work everywhere in real life? Suppose you have gone to the bank to deposit money or are standing in line to buy movie tickets. You have been standing in the scorching heat since 8:00 a.m. and have reached the very front of the line. Then at 10:00 a.m. someone else comes along lazily and stands at the very back of the line. Now what would happen if the bank or ticket counter started working based on the stack rules? The person who arrived last would take the ticket first and head home happily. and you would just keep standing there like you have since morning. Does that make any sense? It wouldn't be fair at all. If that happened, there would be absolute chaos and fighting in the line. It is precisely for situations like this that we need a data structure with the complete opposite rule where the simple rule is whoever comes first gets served first. And this wonderful and perfectly fair data structure is called a Q. The direct meaning of the word Q is a line or a row. When you stand in line at a bank, pass counter or supermarket to pay bill, that is a real life Q. Here the cashier serve the person standing at the very front of the line first. Once their work is done, they leave the line with a smile and the person behind them moves forward. And if someone new wants to join this line, they are forced to go and stand at the very back. They cannot just push their way into the middle or the front. under any circumstances. This simple and beautiful rule is known in computer science as FIFO or first in first out. Meaning the data that arrives at the front of the line first is the first to be processed and leave the line. Basically two main events occur within a que. The process of adding new data or a person to the very back of the line is called NQ. And the process of removing data or a person from the very front of the line once that task is complete is called TQ. To understand this Q concept inside a computer, think about the printer in your office or home. Suppose there is only one printer in an office. But there are 10 computers connected to it. Now in the morning, 10 employees send 10 large documents to be printed almost at the same time. The poor printer cannot print 10 documents all at once. It has to print them one by one. That's when the printer neatly creates a print queue in its own memory. The document request that arrived even a millisecond earlier, the printer places it at the very front of the line and it ences the rest in the back lining them up in order. Then it starts printing the very first document. Once the first one is finished, it removes it from the line, meaning it diffuse it and starts working on the second one. No one interferes with anyone else's work. Everything is completed in an orderly fashion, just like clockwork. Besides this common Q, there are several other great and useful types. For example, the circular Q. When we build a simple queue using an array, we often run into an interesting problem. It turns out that after the people at the front of the line finish their work and leave, the memory spaces at the front remain empty. But because the back is full, no new data can be added. This is a huge waste of memory. The circular Q was born as a great solution to this problem. Here the very end of the line is connected back to the beginning just like a circle or a loop. As a result, even if there is no space at the back, if there is free space at the front, new data can simply wrap around and sit in those empty spots. This ensures not a single bit of memory is wasted. It is widely used in various process management tasks in operating systems. Now, let's talk about the DQ. Another great and special form of a Q is DQ. Its full name is double-ended Q. The rule for a standard Q is that data enters from one end and leaves from the other. But sometimes special situations arise where we need a line where data can be added from both the front and the back and data can also be removed from both ends. This particular two-way line is called a DQ. It is so flexible and useful that you can use it as a stack if you want or even run it as a Q when needed. We have seen that the rules of a Q or line are quite strict. Whoever comes first gets served first. But think about it. Can we always follow this strict rules in real life? Let's try to understand this with a very sensitive and real world example. Suppose you are sitting in the emergency room of a hospital. There is a long line or quue to see a doctor. Perhaps there are three patients sitting in that line. Someone has a mild fever. Someone else might have a cut on their hand bleeding slightly. And someone else has a mild headache. They have all been waiting in line since the morning. Just then a new patient arrives at the hospital with an ambulance siren whailing loudly. They are having a severe heart attack. The person is completely unconscious. Now what if the hospital authorities insist on the strict rules of that common queue? What if they say so what if you are having a heart attack? There is nothing we can do outside of the rules. Go stand at the back of the line. Let the patient with fever and headache be treated first. Then it will be your turn. Just imagine the other patient might die while standing in that line. In such critical real life moments, the rule of a standard queue is completely ineffective. Here we need a smart queue or system where who come first or last is not a consideration at all. Instead, whoever has the highest priority of need will receive service first. Under this rule, a heart attack patient will come to the very front of the line even if they arrive last. Because at this moment their life is the most important priority. Interestingly, computer science has created a data structure based exactly on this hospital model. Its name is the priority queue. Data in a standard queue exists according to the sequence of time. But in a priority queue, a priority value or weight is attached to every piece of data. No matter how or in what sequence you insert the data into the line, when you extract or DQ, the most important data will always come first. Now, a very natural question might come to your mind. How does a computer actually build this priority queue internally? How does it find the most important data out of thousands in the plink of an eye and place it right at the front? To perform this magic, the data structure that the priority Q uses as its engine is called a heap. You can think of a hip as a brilliant and smart organizing system or a pyramid. This pyramid has a very beautiful and strict role. The most important item will always sit right at the very top. Whenever you add new data to this system, the hip immediately shuffles and compares its internal data, arranging it so that the most important data automatically floats up to the very top. There are mainly two types of hips, max hip and minip. If your rule is that the largest numerical value is the most important, then we use a maxim. Here the largest number will always sit at the very peak of the pyramid. For example, if there is a 100 mark exam and we want to reward the person with the highest score first, we will use a max heap. And if your rule is that the smallest numerical value is the most important, then we use a mean heap. Here the smallest number will always sit at the very peak of the pyramid. For instance, in a race, the person who finishes in the least amount of time is the winner. In that case, the mean heap will always bring that shortest time data to the peak for us. Our computers or operating systems are using these priority cues and hips every single day. When you are playing music, downloading a file in the background, and moving your mouse on your computer simultaneously, the operating system assigns a priority to each of these tasks. For a computer, moving the mouse is a task of the highest priority. That is why it processes the mouse input in the priority queue before any music or downloads. This ensures the computer feels completely smooth and fast to you. If you look closely at all the ways we have seen to find data so far, you will notice a common thread. In arrays, we were searching by following indices. In link lists, we were moving along by following one after another. And in the case of a Q, we were waiting in line. But think about this. What if we had data for which we didn't know any index or serial number? What would happen then? Suppose you walk into a huge library or a large bank locker room where 1,000 lockers or cabinets are lined up. You are handed a key with the number 420 written on it. Now, how long might it take for you to find locker number 420 among those 1,000 lockers? You might start working from the very beginning of the rogue. Then you would search until you finally reach local number 420. That is going to take some time. Right now, let's change the scene a little bit. Imagine a completely different picture. Suppose you open the contact list on your smartphone. You might have 1,000 friends phone number saved on your phone. Suddenly, you need to find your friend Rafid's phone number. You don't scroll down through a list of 1,000 names at all. You simply go to the search box at the top and type Rafid. And what about scrolling? What about waiting? In the blink of an eye, in less than a millisecond, Rafit's phone number appears on your screen. Have you ever wondered how this impossibly magical speed is possible? How does the computer pull out Rafid's number directly from a thousand or 100,000 names without any searching or scrolling hassle? This magical data structure that provides such incredible speed is called a hasht. Many programming languages also call it a hashmap or a dictionary. The core philosophy behind how this hasht works is quite fascinating. Its mantra is stop searching, go straight to the location. In other words, direct action. It basically works on a key value pair basis. Meaning it is a rule similar to matching a key to a lock. In this rule, our friend Rafid is our key and his phone number is our value or our asset. When you store data in a hash table, a very smart and high-speed mechanism starts working which is called a hash function. You can think of this hash function as a magical machine. As soon as you provide the name Rafid as input to the machine, it performs a specific mathematical calculation internally. Then in the blink of an eye, it gives you a memory number or an index. Suppose it says drawer number 75. The computer then carefully stores Rafit's phone number exactly in Troyer 75 rather than in 74 or 76. Later, whenever you go to look for Rafid's phone number again, the computer won't search through the entire phone book. It will simply put the name Rafid into that hash function machine again. The machine will immediately say drawer number 75 and the computer will directly open number 75 and hand you the number. Whether your phone book has 10, 1,000 or 10 million pieces of data, searching for anything in a hasht always takes exactly the same amount of time which is close to zero. In terms of speed, this hasht is the undisputed king of the data structure world. There is another very useful member of this hashtable family. Its name is set. To understand what a set actually is, imagine a guest list for a VIP club. That club has a strict rule. The same person cannot enter the club twice under any circumstances and no one's name will be written on the list twice. When we use a regular array list, we can keep the same number or name even 10 times if we want. But as soon as you put this data into a set, it uses its magical touch to trim all duplicate data and keeps each item only once. Interestingly, deep down this set is actually just a variation of our powerful hash table. It just keeps the keys carefully to itself. It doesn't keep any values. And since by hasht rules, the same key cannot exist twice, the set automatically removes all duplicates from our data. So whenever your software needs something like removing all duplicate email addresses from a database or checking in the blink of an eye if a username is already in the system, then the best weapons in your arsenal will be these hash tables and sets. If you look closely at all the data structures we have seen so far, you will see a wonderful similarity between them, they are all linear data structures. This means that here data sits one after another in a well organized straight line or row. Number one, then number two, then number three, just like the carriages of a train. But think about it, does all the information or relationships in our real world always move in such a straight line? Absolutely not. Most relationships in our real life are hierarchical or layer based. Here many people remain under one person and many more remain under them. Let's give a very beautiful and familiar example. Our family tree. Think about your own family for a moment. At the very top is your grandfather. Your grandfather's children are your father and your uncle. Meaning two branches spread out in two directions from your grandfather. Again, your father's children are you and your sister, meaning two new branches were created from your father's branch. On the other side, your uncle's child is your cousin. Another branch emerged from your uncle's branch. Take a look. Can you arrange this entire relationship in a straight line or an array? Who would come after the grandfather, father or uncle? And who would follow the father? Trying to arrange it in a straight line would make the whole relationship tangled and meaningless. To explain this kind of branching and parent child relationship, we need a completely new type of data structure. It is called a tree. However, there is a small but very interesting difference between real world trees and computer science trees. Real trees have their roots under the ground and their branches spread towards the sky. But a computer tree is exactly the opposite, an inverted tree. Its root is at the very top just like the grandfather in our family tree. and its branches spread downwards. In this magical world of trees, the very first data at the top is called the root which has no parent. The data from which new branches emerge is the parent and the branches below are called children. The data at the very end of the tree which has no further branches or children is called a leaf. For example, consider yourself, your sister and your cousin. That is if you don't have children yet. If you do, that's a different story. Inside computers, these trees are used constantly every single day. Take your computer's folder system or file explorer for instance. At the very beginning is your C drive which is the root. Inside this C drive are folders named program files, users and windows. These are the children of the C drive. Then inside the users folder, there are pictures, music and documents folders. like this one folder inside another and more folders inside those. This entire system is actually one massive living tree. The most famous tree in the tree family is called a binary tree. The word binary means two. A tree where each parent can have a maximum of two children. One is called the left child and the other is the right child. We call it a binary tree. It cannot have more than two children under any circumstances. And when a special rule is cleverly added to this binary tree, it becomes one of the most powerful tools in the programming world. The binary search tree or BST. The rule for a binary search tree is very simple. The data in the left child of any parent must be smaller than the parents value. And the data in the right child must have a value greater than the parent. This simple rule gives us a great advantage. Let's recall that popular childhood number guessing game. Suppose I have thought of a number between 1 and 100. You have to guess it. You will say a number each time and I will only answer whether my number is greater or smaller than the number you said. Now if you foolishly start guessing in a straight line like 1 2 3 4. It might take you up to 100 tries. But if you are smart, your first guess will be the middle number which is 50. If I tell you my number is smaller than 50, notice what magical thing just happened. With 1 second of questioning, all 50 numbers from 51 to 100 were eliminated from your list of possibilities in one go. You don't even have to look in that direction anymore. Now you will only search between 1 and 49 right in the middle. Next, you said 25. I said my number is greater than 25 and instantly 1 through 24 are gone. In this way, by guessing the middle number each time, we cut our search area exactly in half at every step. Even if you search through 10 million data points using this method, you can find the correct number in just 23 to 24 guesses. Our binary search also organizes data in memory following the rules of this magical guessing game. Whenever you go to search for data, it first compares the data with the root. If the data is smaller than the root, it goes straight to the left and discards all thousands of data points on the right forever. As a result, searching for any data, adding new data or deleting it happens at an incredibly fast speed here. But there is a small danger hidden here as well. Suppose you are going to add some new numbers to a binary search tree. But instead of giving the numbers randomly, you start giving them in a sequential order for small to large like 1 then 2 3 4 5. Now close your eyes and think about it. According to our rules, what would be the tree look like? Initially our root is 1. Then came two. Since the number two is greater than one, it will sit to the right of one. Then came three. It is larger than two. So it will sit to the right of two. Then when four arrives, it will sit to the right of three. This tree has no branches on the left side at all. All the data has just gone down in a straight line to the right. It doesn't look like a tree anymore. Instead, it has taken the form of our old long straight line of a link list. And whenever our tree leans to one side and turns into a straight line, the speed of our magical guessing game is completely destroyed. Now if you want to find the number five, you have to pass through 1 2 3 4 and walk straight to reach five. To save us from this serious problem, balance trees have arrived in the world of trees. The two most famous members of this family are Avl trees and red black trees. Here the full form of Avial tree is Adulen Welsski and Landis tree. These words came from the name of the inventors of this data structure. The superpower of a balance tree is its ability to maintain its own balance. Whenever you add new data, if it sees the tree growing too heavy or tall on one side, it immediately twists its branches to spread the tree evenly again. It never allows one side of the tree to grow taller than the other. As a result, the tree always remains perfectly balanced and the search speed is lightning fast. Our modern large scale databases use these balance trees for data indexing. So much for the story of maintaining balance in the world of trees. Now let's get acquainted with a completely different and amazing type of tree which is also called a tree. The pronunciation is the same as tree but the spelling is different. Some people however call it a try. The name comes from the word retrieval. To understand this type of tree, think of a very familiar daily experience. When you go to the Google search box and type how to even before you finish the sentence, Google immediately shows you several popular search suggestions or the way the autocomplete feature works when you type on your phone. How does the computer figure out which words can be formed from just two or three letters out of a vast dictionary of one or 10 million words? The data structure that works day and night behind this incredibly fast autocomplete magic is our tree. The way a tree works is completely different. In a regular tree, we store an entire word or number inside each node. But in a tree, we don't store full words. In every node, we store a single letter of the English alphabet. Suppose we want to store two words in our tree, car and cat. The tree will first create a branch from the root for the letter C. From that C, the next branch will extend for A. Now notice the first two letters of both car and cat are exactly the same C and A. So the tree will not create C and A twice in memory. It will share the same C and A path as a common route for both words. Then from A the path will split into two separate branches. One branch will go toward R and the other will go toward D. Now think about this. Even if our dictionary had a 100,000 words starting with C, they would all begin their journey from that single C branch. This results in a massive saving of memory. And when you go to the Google search box and type only CA, the computer goes directly from the root to the C branch, then to the A branch where it looks down to see how many branches extend below it. It will see that one branch goes to R and the other to T. And just like that within a millisecond it will show suggestions on your screen asking if you mean to search for car or cat. For word searches, spell checkers or search engine autocomplete features. So far we have looked at linear data structures that look like straight lines. We also saw hierarchical data structures that spread from the top downwards. There is always a parent there and under it there are some children. But now let's think about some of the largest networks in our real world. For example, social media platforms like Facebook or LinkedIn. On Facebook, you are my friend and I am your friend. Again, your friend is Rafid. Rafid's friend is Tanvir. This is a huge cycle. Who is whose parent here and who is whose child? Is there even any rule that your friends must be under you? Absolutely not. Everyone on Facebook is connected to everyone else in parallel. This is not a straight line, nor is it a tree structure depending from top to bottom. It is a fast complex network that spreads in all directions like a spider's web. Now consider Google maps. There is a road to go from Dhaka city to Chittagong. You can also go from Dhaka to Cellet. On the other hand, there is also a bypass road from Cellet to Chagong. Here every city is connected to one another through various roads. There isn't just one fixed path to travel from one city to another. There are countless alternative paths. The data structure used to store this complex and interconnected relationships of the real world in computer memory is called a graph. In simple terms, in the world of data structures, a graph is the most independent and flexible member. It has no strict rules or regulations. Anyone can connect with anyone else whenever they want. They can create as many connections as they like. It's basically free mixing. To get to know this strange world of graphs well, we need to be familiar with two fundamental things. The first one is the vertex. Vertex refers to the core data points of our network. For example, on Facebook, every person's profile is a vertex or in Google maps, every city is a vertex. And the second thing is the age. An edge is the connection or path between two vertices. The friendship between two people on Facebook is an age. Again, the road between two cities in Google Maps is also an edge. Based on the type of these ages or connections, graphs can be divided into several categories. First, let's talk about the undirected graph. This is much like our Facebook friendship. If you send a friend request to someone on Facebook and they accept it, the relationship is established from both sides. If I am your friend, it means you are also my friend. This connection has no specific direction or one-way arrow. Both can access each other's profile with equal rights. This wonderful network of two-way relationships is called an undirected graph. Now, let's think about Twitter or Instagram. If you follow a famous celebrity there, it doesn't mean that the celebrity follows you back. The relationship here is completely one way. information or updates will only come from their profile to yours. None of your news will go to them. This type of network with oneway directional arrows is called a directed graph. Let's go back to Google maps. Suppose there is a road from Taka to Chagang and there is also a road from Dhaka to Cellet. The two roads are not the same. The distance from Dhaka to Chitagang might be 250 km taking 5 hours. On the other hand, the distance from Dhaka to Sillet might be 240 km. But it takes 6 hours. When each connection or road in our graph is associated with a calculation of distance, time or cost which we call wet, it is called a weighted graph. Google maps or Uber always uses this weighted graphs to calculate exactly which route will save you both time and fuel. And if there is no calculation of distance or cost between the connections, what do we call it? For example, my friendship with you on Facebook has no kilometers or weight attached to it. This kind of simple connection is called an unweighted graph. Finally, let me tell you a great truth. All the studying we did about trees. Trees are not actually things from another planet. A tree is just a special form of a graph. If you apply two strict rules to a graph, first there cannot be any cycles, meaning there should be no path that loops back to where you started. And second, every child must have only one parent. Then you will see that the graph magically transforms into a tree. Once you understand this small relationship, you'll be surprised to see that everything from arrays to graphs are actually members of the same family. They have just taken on different forms to meet our various needs over time. So far we have seen how our data can be neatly organized in computer memory. We made movie theater seats with arrays, treasure hunt chains with link lists, stacks of plates with stacks, ticket cues with cues, magic drawers with hashts, family trees with trees, and a giant spiderweb with graphs. But think about it, is our job done just by organizing data in memory like this? Suppose you bought a filing cabinet for your desk as a hobby? You organize the papers neatly in folders. But if you sit in front of that cabinet all day just staring at it without taking out any papers, reading them or doing any new calculations, then what was the point of building such a wonderful cabinet? A data structure is essentially a house to store your data. But the real work is with the data kept inside that house. We might need to find specific information from among billions of data points. You need to organize random data neatly from smallest to largest. or like Google Maps, you need to find the shortest and cheapest route from one city to another. The specific and disciplined method you use to handle this data, solve problems, and reach an accurate result through step-by-step calculation is professionally called an algorithm. In simple terms, data structure is the science of where and how we store things. And algorithm is the art of how we use those stored things to perform tasks and solve problems. One is absolutely useless without the other. Just as science is useless without arts. The first task we encounter when stepping into the world of algorithms is searching or finding something. Honestly, our entire digital world stands on this searching. In computer science, there are mainly two primary methods for searching data. Linear search and binary search. Let's start with linear search. Suppose you got a huge 100page register book from your college. It contains the names of 1,000 students. But the trouble is the names are not sorted alphabetically. They are completely random. Now if you are asked to find the name Tanviri Ahmed from that book, what options do you have? You are forced to open page number one. You have to read the first name, then you have to read the second name. This way you have to check every name line by line until Tanvir Rahmed is found. This method is called linear search. Here the computer starts from the very first index of an array or list and checks the data one by one until the end. The problem arises when Tanvir's name is on the last line of the last page of the book. You have to go through the trouble of reading all 1,000 names. If the data is 10 million, the computer will have to check 10 million times. It is clear that this is extremely slow. The second method is binary search. Now imagine you are not given a random book. You are given a huge thick Oxford English dictionary containing 100,000 words all sorted alphabetically from A to Z set. Now if you are asked to find the word monkey, you surely wouldn't start reading line by line from the first page, right? You directly open the dictionary right in the middle. Suppose after opening the middle, you see that word starting with the letter M are there. But the page is for the word mango. You know very well that in the English alphabet the letter O in the word monkey comes much later than the letter A in the word mango. This means you are certain that the word monkey cannot possibly be in the left half of the dictionary. You immediately eliminate that entire 50,000word section on the left side of the dictionary in the blink of an eye. Now you open the remaining right half of the dictionary right from its middle. Perhaps you found nose there. You realize that monkey must be before nose. Immediately the entire right half is discarded. By opening from the middle each time you are halfing your search area with every step. This magical method is binary search. In a dictionary of 100,000 words, a linear search could take up to 100,000 checks. With binary search, you can find the word by opening the pages at most 17 times. However, there is one thing you must keep in mind. The main condition for binary search to work is that your data must be presorted. If the data is scrambled, binary search will not work. Then linear search remains your only hope. And this concept of dividing in the middle and discarding half is exactly what we saw inside binary search. We saw that to use binary search the data must be sorted. But in real life when we get new data it doesn't come neatly organized on its own. It comes in a completely random state. The algorithms we use to transform this chaotic disorder into order are called sorting algorithms. Let's get acquainted with a few such excellent sorting algorithms. First comes bubble sort. What happens when a bubble of air or gas forms underwater? It slowly floats up to the surface. Bubble sort works exactly on this principle. It compares two adjacent numbers starting from the very beginning. If it sees the front number is larger than the back one, it immediately swaps their positions. By comparing side by side like this, the largest number in the list floats just like a water bubble to the very end of the list and settles in its correct place. It repeats this entire process until all the numbers are sorted correctly. The method is very easy to understand, but it works extremely slowly when there is a lot of data. Next comes the selection sort. Suppose 30 students are standing in a classroom with random heights. The teacher wants to line them up from the shortest to tallest according to their height. The teacher will look at all 30 students and the shortest student among them will be pulled to the front and placed in the first position in the line. Then ignoring that first student, the teacher will pick the shortest among the remaining 29 students and place them in the second position. This method of picking the smallest from the remaining students each time and placing them in the correct spot is selection sort. The third method is insertion sort. When you play cards with friends, how do you arrange the new cards when they're given to you one by one from the deck? Suppose you already have three cards arranged in your left hand. 2, 5, and 9. Now you pick up a new card in your right hand. Suppose it is seven. You will compare the seven card with the cards in your left hand. You'll see that seven is smaller than 9, but it is larger than five. You immediately create a small gap between the five and nine cards and insert the card right into that place. This method of taking new data one by one and inserting it into the correct position within the already sorted part is called insertion sort. It works quite fast when the amount of data is small. These three simple methods are good for small tasks, but they will completely fail when trying to sort 10 million or 100 million data points. So for large data, we need more powerful weapons. Marge sort is a very intelligent algorithm. It doesn't try to solve a huge problem all at once. It believes that no matter how big a problem is, break it into small pieces. Suppose you have a list of eight random numbers. Marsort will first cut these eight numbers in the middle and divide them into two groups of four. Then it will cut this four into two groups of two. After that it will cut the two into single pieces making eight separate individual pieces. A single number is already sorted by itself. Right now marot will take two single numbers at a time from the bottom. It will compare them and pair them up in the correct order or merge them by joining this small sorted pieces together like this. In the end, it will create a perfectly sorted list of all the eight numbers. The speed of this method is super fast. Another fast-paced method is quick sort. It first chooses any number from the list as a leader or pivot. Suppose it makes the number 50 our leader from the list. Now quick sort will run through the entire list once and bring all the numbers smaller than 50 to its left side and it will bring all the numbers larger than 50 to its right side. As a result, our leader 50 will land in its exact correct position because everything to the left of 50 is smaller and everything to the right is larger. Now quick sort will choose a new leader for that small left section and it will choose a new leader for the large right section by dividing into small groups and selecting leaders. This way a list of millions of data points will be sorted in the blink of an eye. In real life when we call a sort function in most of the world's programming languages quick sort or mar sort silently works for us behind the scene in memory. Now we'll talk about a concept that feels like a puzzle when heard from the first time or seen in court. This wonderful thing is called recussion. Simply put, when a task or function calls itself repeatedly to solve its own problem, that is recussion. Giving two examples from real life will make the matter crystal clear in an instant. Have you ever been to a salon or dressing room where there's a huge mirror on the wall in front of you and another one right behind you? Have you ever noticed what happens when you stand in the middle? You can see the back mirror inside the front mirror. And inside that back mirror, you see the front one again. Inside that another smaller one with you looking even smaller. And this image continues to repeat into infinity getting smaller and smaller. One mirror reflecting itself over and over. This is recursion in its living form in nature. I can give you another example. For those who have used the OBS screen recorder, if you select your desktop as a scene in OBS, you'll see the fun. You can see an infinity recursion there as well. Or consider those famous Russian wooden dolls. If you open the lid of a beautiful wooden doll, you can see that inside it looks exactly the same, but there is another doll sitting inside that is a bit smaller. Opening that one will reveal a third, even smaller doll. a smaller version of the same doll hiding inside the belly of the larger one. This is recursion. In the world of programming, it is famously called the Russian nesting doll. Suppose I ask you to find the sum of all numbers from 1 to 100. If you think in terms of recursion, you might say adding 1 to 100 is quite a task. Let's do this. Set the number 100 aside and tell my younger brother to get me the sum of numbers from 1 to 99. Once he brings it, you add 100 to it and that's it. But your younger brother isn't that foolish either. He sets the number 99 aside and calls his younger brother to bring him the sum from 1 to 98. In this way, each brother keeps calling a smaller version of himself to solve a problem that is one step smaller. The call eventually reaches the very youngest brother who has only one number in his hand which is one. Then that little brother will say the sum of one is just one. He doesn't need to call anyone for that. He sends the one back to his older brother. He adds two to it and sends it back to his older brother. In this way, the sum builds up from the very bottom one after another until it finally reaches your hands and you get your desired answer. 5050. Notice that the last little brother for whom the problem became so tiny that there was no need to call anyone else. In programming terms, this magical moment is called the base case or the stopping condition. If you don't provide this correct base case in recussion, you are in big trouble. The code will then keep looping forever. Just like the two mirrors in the salon, on one point, the computer's memory will be completely filled up and the program will crash with a critical error which is called a stack overflow. Whether it's merge sort, quick sort or the stories of three data structures we have heard, recussion is the most intelligent and precise way to handle them. Do you know why? Because if you look closely at every branch of a tree, you'll see that it is actually a small tree itself. An extraordinary application of this recursion and a almost magical practical implementation of it is backtracking. The name itself suggests following your own footprints back to the starting point. Take your daily life for example. When we look for a path in an unfamiliar place, we start walking down a road. If we suddenly hit a high wall or a dead end while walking, do we just sit there and give up? Not at all. We calmly retrace our own footsteps back to exactly where we came from, to the point where we took the wrong turn. Then standing there, we try a different path. Moving forward on a path and stepping back the moment we see an obstacle or dead end and searching for a new path. This entire clever technique is called backtracking. In computer science, this concept is perfectly explained by the popular puzzle game sudoku. You must have seen the 9 into 9 grid it uses. And numbers from 1 to 9 have to be placed so perfectly that no number repeats in any row, column or 3 into three box. Now, do you know what a computer does when it is given a different sudo to solve? It first tries placing a one in the very first empty cell. If the rules aren't broken, it confidently moves to the second cell and places a two. It keeps moving forward like this step by step. But as it progresses, let's say it reaches the 25th empty cell and realizes that no matter which number from 1 to 9 it places, it breaks one rule or another. There is no way to move forward. A complete dead end. Right at this point, our clever backtracking algorithm doesn't panic at all. It quickly calculates that since nothing works in the 25th cell, it must have placed an incorrect number in the 24th or 23rd cell earlier. In an instant, it steps back from 25th cell to the 24th. It clears the previous wrong number and attempts to place a new correct one. Even if it doesn't find a solution in the 24th cell, it takes another step back to the 23rd cell. By relying on this magic of retracing footsteps when a mistake occurs, correcting it, and trying a new path, the computer solves the world's hardest sudoku in just a few milliseconds. Even the AI in computer chase games use this backtracking to mentally explore all possible paths for 10 to 15 moves ahead. And whenever it sees a tent, it quietly steps back and makes the best possible move. Most complex relationships in our real world are actually like graphs or networks. Everything is interconnected much like a spider's web. Now think about it. If we set out to find something within this massive web or you want to walk from one city to another, how exactly would you proceed? A network where countless roads branch out from every intersection. Walking randomly with your eyes closed there. It's only natural to get lost. You might find yourself going in circles trapped in a maze. To work through these complex graphs or trees in an orderly fashion without getting lost, we primarily have two algorithms at our disposal. The first is called depth for search or DFS for short. And its way of walking is quite strange. As long as there is a road ahead, don't even think about looking back. Dive straight to the very end of the boundary. Imagine you have entered a massive dark maze. There are three paths open in front of you. to the right, to the left, and in the middle. If you walk using the TFS method, you would pick one path, let's say the one on the left. Then you would keep going deeper and deeper along that path. You do not stop until you reach the very end of the road or hit a dead wall. Only when you reach the end and see there are no more paths do you use backtracking or retrace your footsteps back to the previous junction. Then from there, you dive deep again into another unexplored path. For this entire strategy to work properly, we need the help of a stack or recussion because we have to store and remember the junctions we left behind in a stack as we moved forward. The second technique is called bread for search or BFS. Its main philosophy is very simple. Before jumping far away, take a good look at those close to you. Think of a calm steel pond. You throw a small pebble right into the middle of the pond. The ripple created the moment the pebble hits the water spreads out perfectly in a circle, doesn't it? At first, it's a tiny circle or the very immediate area. Then that circle gradually grows larger and moves to distant areas. BFS works exactly by the rule of this bond ripples. Suppose we start our search from your profile on Facebook's massive network. BFS won't jump straight away to your friend's friend's friend. It will first check the profiles of everyone in your immediate circle. That is your first level direct friends. Just like that first ripple in the pond. Once it finishes checking all your direct friends, it will step into the second level. Meaning it will start checking all the friends of your friends one by one. In this way, it spreads out evenly level by level to scan the entire network. This beautiful sequence. First the people close by, then the ones further away. To keep this sequence in memory, we need the help of a Q. When Facebook or LinkedIn shows you people you may know or friend suggestions, they are actually using this magical BFS algorithm. Now let's think about this in a different way. In real life, when we leave home to head somewhere, what is our main objective? It is how quickly we can reach our destination in the least amount of time and at the lowest cost. Isn't that right? this weighted graph from one city to another finding the shortest and best route which we call the shortest path. How do we find that? The world famous algorithm that provides the solution to this great problem is called Tastra's algorithm. The funny thing is that Dutch computer scientist Edgar Destra reportedly discovered this groundbreaking algorithm while simply drinking coffee. Assume you are now in Dhaka and your destination is Chitagong. You have to pass through several cities or junctions in between and every road has a specific cost or a distance in kilometers. The core strategy of Mr. Das's algorithm is quite beautiful. Forget about the future at this moment. Always choose the cheapest or the closest junction at your hand. Initially you are standing in Dhaka. So the distance from Dhaka to Dhaka is zero. And for all the other cities say Kumla, Feny or Chitagong, you don't know their distances yet. So for the time being they are assumed to be infinite or very far away. Now let's calculate the direct roads that go out from Dhaka. Suppose one road goes to Narang Gonch with a distance of 20 km. Another one goes straight to Kumla which has a distance of 100 km. Destas algorithm will then quietly note down the cost to reach Narendon as 20 and the cost to reach Kumla as 100. Then it will ask itself well which is the cheapest city at hand right now. The answer is very simple. Narang Gon is only 20 km away. Then without any delay it will immediately move to Narang Gonch. Standing there it will look at where else one can go from there. It says there is a wonderful bypass road from Narang to Kumla whose distance is only 50 km. Now notice that we previously knew the cost to go directly from Dhaka to Kumla was 100 km. But now we see that Dhaka to Narang Gon is 20 km and Narang Gon to Kumla is 50 km. Meaning the total cost comes to only 70 km. Now you tell me is 100 km cheaper or 70 km? certainly 70 km. Tyra's algorithm will then immediately cross out that old 100 km figure and write the new cheaper cost there. The act of crossing out the old calculation and writing the new cheaper one is called relaxation. By standing at every junction and always choosing the cheapest path by the time it reaches Chitagang, the lowest cost route from Taka to Chitagong will be created in your hand like magic. And this ability to stand at every intersection and find the shortest path in the blink of an eye is powered by Tastra's algorithm which uses a mean hip or priority queue. The very thing we just learned about as its engine. Today, whenever you pull your phone out of your pocket, open Google Maps or Uber and see those directions with a beautiful blue line appearing on the screen, know that right behind that line, our Destas algorithm and priority Q are working tirelessly. Almost all of the thousands of algorithm in the world are fundamentally built upon four core philosophies. Once you grasp these philosophies, you'll be able to understand and even create new algorithms yourself. The first of these philosophies is called the greedy approach. In the world of algorithms, being greedy has a wonderful meaning. The core idea is to stop worrying about what might happen in the distant future for now. Just grab the option that seems most profitable or best right in front of you at this very moment without any hesitation. To understand this, let's think about a shopkeeper giving back change. Suppose you go to a store and buy items worth 68 taka. You give the shopkeeper a 100 taka note. He needs to give you 32 taka back in change. The shopkeeper's goal is to return this 32 taka using the fewest number of notes or coins possible. He first looks at the largest note in his cash box. 50 taka is larger than 32 taka. So he cannot give that. Then he picks up the next largest note which is 20 taka. Without calculating anything for the future, he greedily hands you the largest 20 taka note. 12 taka remains. Now to settle this 12 taka, he again looks for the largest note in his box. He picks up the 10 taka note. Two taka remains. Now to settle the two taka, he simply hands you a two taka coin. Notice how perfectly he settled your 32 taka change using only three notes or coins. At every step, he chose the largest option available at that moment and that resulted in the best solution for the entire problem. TA's algorithm works using this exact same strategy. But yes, one thing must be remembered. The greedy approach cannot provide the best solution everywhere. Where a momentary gain can cause damage later on, we must turn to other philosophies. Let me give you a small example. For instance, when you go to purchase an educational course, generally good courses are more expensive, but you always try to choose the one that is cheaper. In this case, Triasto's algorithm will not work. The second philosophy is called divide and conquer. The ancient Roman Empire ruled the entire world by utilizing this very policy. Their strategy was brilliant. Instead of engaging in a direct frontal war with a massive and powerful enemy force, they would strategically create divisions among them. Break them down into small groups. Once the enemies are divided into small and weak groups, you can easily defeat them by fighting each group one by one. And once all those small groups are defeated, the entire empire will be in your hands. In computer science, this philosophy works in three steps. The first task is to break the massive problem in front of you into smaller sub problems. Next, solve or conquer these small problems individually, usually by using recussion. And at the very end, combine those conquered solutions together to construct a complete solution to the main problem. The mar sort and quick sort that we have heard of are excellent examples of this divide and conquer philosophy. Just like Mars sort takes 10 million pieces of random data and keeps cutting them down into individual small pieces. Then it sorts them into small pairs and conquers them. And finally, it joins those sorted pieces together to give us a perfectly sorted list of the entire 10 million data points. Binary search also does the exact same thing. every time it opens a book from the middle house the problem and finds the correct word. The name of the third philosophy is dynamic programming which is known as DP for short. Its core concept is so simple that even a small child could easily understand it. Its entire philosophy stands on a very simple piece of real life intelligence. Suppose a task or calculation you once struggled to do in the past. Write down or remember the result of that calculation somewhere. If you need to perform the exact same calculation again later, would you foolishly repeat all that same hard work from the start? Not at all. You directly use the previous result you remembered. Suppose I write 1 + 1 + 1 + 1 + 1 on the board in front of you. How much is it? You count quickly and say five. Now I add another + one to the far right of the same equation. It won't even take you a second to find the answer. You'll immediately say six. You didn't sit there and count from the beginning this time because you know that adding the previous five ones equals five. So you simply added the new one to the old result of the five that you had remembered. This magical process of writing down or remembering the results of our past calculations in memory or a table is technically called memorization. Think about the Fibonacci series in mathematics. There every new number is the sum of the two numbers immediately preceding it. If you ask a computer to find the 50th number of the Fibonacci series using simple recussion, it will perform the same small calculations billions of times without even realizing it. It could take hours or even days for the test to finish. But if you add dynamic programming or memorization to it and tell the computer, hey, just write down the calculated result in a diary, then the same calculation that took the computer days to solve will be done in a second. So whenever you see the same small problem recurring in a complex task, you will know it's time to use dynamic programming. And the fourth philosophy is the very familiar backtracking. We have seen this in the solutions to sudoku and mages. When you have countless alternative paths in front of you and you have to try them all to find the correct solution and if you hit a dead end, you have to step back and take a new path. That is exactly when backtracking becomes our best tool. Think deeply for a moment. Did any of the topics or concepts I just talked about fall from the sky? They didn't. When it became difficult to insert data in the middle of an array, the link list was born from that very problem. When we needed to control the sequence of data storage, stack and Q emerged. When we needed the speed to search for data in the blink of an eye from thousands of records, hash tables and binary search trees were born. Again, when we needed to store real life complex networks and relationships in memory, graphs came along. Every data structure and every algorithm is connected to one another at the root. Together, they form a vast and beautiful family that keeps our world of software and technology running. Knowing these concepts will create a very powerful and clear map of the entire subject in your mind. Now, it is time to put this knowledge into practice. Pick any programming language of your choice and start building the concepts we learned today in your memory by writing the code yourself. When you write the code yourself, you won't be blindly memorizing anything anymore. You will feel exactly what magical events are happening inside the memory behind every line of your code. Happy coding.

Generated algorithmically for Search Engine Indexing.

Summarize Another Video