Imagine you walk into work and your boss says, “I just got a list of 2 billion numbers, can you sort them for me as soon as possible?”

You might be shocked and wonder where to even start the problem. Do you try and do it all by hand and spend the next couple years trying to sort even a small fraction of the values? Or is there some better way…

The Essential Algorithms and Data Structures is the most comprehensive course on the topic on Udemy and together we will learn how to solve problems like these and even more complicated problems. Algorithms are a guaranteed way of solving a type of problem that works in a predictable fashion with the data. Algorithms like sorting algorithms can be used to sort 10 values or a billion values and won’t need any modifications to work with either set. Other algorithms allow us to efficiently search a set of data or find the lowest cost option to connect a series of points on a graph. Algorithms are like blueprints that we use to solve problems in our programs.

Data structures are unique ways of storing data that are optimized for certain situations. Data structures like a priority queue allow us to model how a CPU processes requests, or how to efficiently model a set of cities and interconnecting flights. Choosing a good data structure to store data can make programs millions of times faster than a bad choice. Data structures are like the power tools of programming that let us drastically speed up our programs.

In this course we’re going to combine data structures with algorithms to create a powerful arsenal you can use to solve whatever problems show up in your code. We start by discussing time complexity and how we use it to analyze algorithms. We then cover the most important algorithms for interviews and discuss how to perfectly answer common interview questions. We then shift our focus to being able to search efficiently depending on the starting set of data. In addition, we cover the eight most essential algorithms for sorting and discuses when to use each of them. After that, we cover fundamentals for data structures like generics and recursions that are essential for almost all data structures. Then, we shift our focus to the essential data structures like maps and sets that every powerful programmer is expected to have mastered. Next, we go into detail with the three most important types of trees (Binary Search Trees, Red-Black Trees, and AVL Trees). Finally, we wrap up our discussions with hashing and graphs, which are essential to higher-order approaches for computer science.

While other courses on the market focus entirely on theory we will place a major emphasis on being able to actually implement the algorithms and data structures we cover. We’ll go over how to modify an algorithm or data structure for your situations and will always be looking at pseudo code that helps us understand how an algorithm or data structure works. In addition, we always cover the theory in detail and focus on understanding how and why a data structure is efficient or the details of an algorithms approach, so you can implement it in your language of choice.

We will take a Java-based approach for our discussions of how to implement an algorithm but this doesn’t mean you have to know Java. Java is a generic style language whose attributes are almost identical to other major languages like C++ or Python.

If you have any questions you can depend on prompt communication from me. I pride myself on responding to questions within 24 hours and work hard to ensure that each student is satisfied. If you have any questions at any time my email and message box are open 24/7!

I hope you’re as excited as I am to begin this journey through the most interesting parts of Computer Science. Personally I can say that once I learned about algorithms and data structures I was pleasantly surprised with how many new problems I could solve and how fluently I could understand professional level discussions of programming. If you want to go from being a simple programming student to a true software engineer, then join the tens of thousands of satisfied students and enroll today!

### Introduction to Algorithms

In this lesson we cover the basics of algorithms such as what an algorithm is, why we study them, and the restraints that we must work around.

In this lesson we cover the process we take to create an algorithm, how we evaluate an algorithm, and explain why we use worst case analysis in most cases.

In this lesson we cover how to properly notate an algorithm's time analysis. We also cover mathematical equations that use big-O notation and the four main styles of algorithms. After this lesson you'll be able to describe your algorithms using technical conventions.

In this lesson we cover how the various forms of a growth rate can quickly cause large differences in their performance. After this lesson you'll be able to understand why we describe performance in terms of growth rate instead of running time.

### Interview Algorithms

In this lesson we cover the easiest method of finding the GCD of two numbers, the brute force method. After this lesson you'll be more comfortable with Big-O notation and understand why we don't always use the brute force algorithm.

In this lesson we cover how to implement a more efficient GCD algorithm based on Stein's famous method. By the end of the lesson you'll understand why Stein's method is preferable to the brute force method but still has major shortcomings.

In this lesson we cover the most efficient GCD algorithm, Euclid's recursive method. We cover how to respond to interview questions that come from the algorithm and why we almost always use the Euclid method.

In this lesson we cover the famous FizzBuzz interview question. We work to understand why it is such a common question and how to make sure you nail any FizzBuzz type questions using a systematic approach.

In this lesson we cover the most important algorithms surrounding string reversal. We cover common questions and their best answers. We also cover why the complexities are so important to understand in detail.

In this lesson we cover the brute force method of generating all the prime numbers from 2-n. By the end of the lesson you'll understand why finding primes is such a relevant interview question and the time complexity of the brute force method.

In this lesson we cover the more efficient sieve based method of prime number generation. We cover the sieve method's advantages and disadvantages and cover common ways a person could modify the algorithm.

In this lesson we cover the best way to answer common questions on palindrome checking. We cover inherent limitations in the problem and explain how to solve the most complex modifications of palindrome checkers.

### Searching and Order Statistics

In this lesson we cover the search method linear search. We explain why linear search is like the Swiss-army knife of searching algorithms and explain the time complexity of linear search.

In this lesson we cover how to binary search an already sorted array. We cover the advantages and disadvantages of the search method and explain why it is considered such a fundamental search. We also cover the time complexity and memory complexity depending on implementation form.

In this lesson we cover exponential search which is a modified version of sorted search that is optimized for a very small set of circumstances. We cover why exponential search is so important and how to apply the principle to our programming as a whole.

In this lesson we cover Interpolation Search, which is a modification of binary search that works best in a uniform set. We cover why Interpolation Search is superior in uniform arrays and explain the time complexity cost of this.

In this lesson we cover how jump search works based on a less even way of traversing the array. We explain the advantages and cover how the time complexity is naturally apparent based on the algorithm's function.

In this lesson we cover the brute force method way of finding the minimum and maximum of a set. By then end of the lesson you'll understand why finding the minimum and maximum is surprisingly difficult and the limitations of big-O notation.

In this lesson we cover the expected linear time and worst case linear time complexity algorithms for finding the Nth lowest value. We cover how it is based on recursion and how effective more efficient processing can be for our programs.

In this lesson we complete our discussion of Nth lowest by expanding on the details of how the randomized partition median method works and explain the time complexity in detail. By the end of this lesson you'll understand the many ways we can find the Nth lowest with varying efficiency.

### Sorting Algorithms

In this lesson we explain why we study sorting and why sorting is such a fundamental topic of study for Computer Science. We also cover the different types of questions and constraints one can have with sorting.

In this lesson we cover the basics of Insertion sort. We cover why insertion sort is such an intuitive algorithm and relate it to how a person sorts a deck of cards. We then cover the procedure for implementing insertion sort.

In this lesson we cover the time complexity of insertion sort. We discuss how the time complexity originates and describe the situations where insertion sort should be used.

In this lesson we cover the basics of selection sort. By the end of this lesson, we will understand why we have selection sort and how it differs from insertion sort.

In this lesson we go over the time complexity of selection sort. We discuss how the complexity originates and how it differs in the real world from insertion sort's running time.

In this lesson we cover the basics of how bubble sort works. We explain why it has a bad reputation and why it is still considered a prominent sort. By the end of the lesson you'll understand the implementation details of bubble sort.

In this lesson we cover the time complexity of bubble sort and explain why bubble sort has such a bad time complexity compared to other similar sorting methods.

In this lesson we cover how quicksort works at a general level and how it depends closely on recursion and a divide and conquer approach to sorting a set. We also explain how quicksort is similar to the Nth lowest algorithm.

In this lesson we cover the fundamentals of how we can actually implement quicksort in our own programs and explain why quicksort has a natural advantage over similar sorting algorithms.

In this lesson we cover the time complexity of quicksort. By the end of the lesson you'll understand why quicksort is faster than previous sorting methods and where quicksort is at optimal performance.

In this lesson we cover the basics of how mergesort works. We explain the baseline principle and how it has a slightly atypical complexity ordering. We also cover how the merge step works in reality.

In this lesson we cover how to actually implement mergesort. We cover how mergesort depends quite a bit on how you choose to implement the algorithm, and how mergesort is one of the easiest algorithms to implement using recursion.

In this lesson we cover how mergesort compares similarly to quicksort's complexity. We explain how mergesort's running time depends quite a bit on the implantation method and explain why mergesort is so memory hungry compared to other comparison based sorts.

In this lesson we cover Heapsort, the first data structure based sort. We use heap sort as a quick look ahead to data structures. We address the types of heaps used to sort and cover the heap rules.

In this lesson we discuss how heapsorting is preformed with a heap and how we form the sorted array. We also discuss the 3 main tasks we need to implement.

In this lesson we cover how searching inside of a heapsorted set works. We cover this with a algorithm, then cover a demo, and finally explain each of the steps in detail.

In this lesson we discuss adding an element to a heap. By the end of the lesson you'll be able to add an element to a heap and understand how it works.

In this lesson we discuss how to remove a value from a heapsorted set. By the end of the lesson you'll understand how and why removal from a heap works as it does.

In this lesson we cover the time complexity of the major operations with heapsort and heaps in general. We also wrap up our discussion of heapsorts.

In this lesson we discuss the inherent limitations of comparison based sorts. We then explain how we can beat these limitations and cover the basics and notation of counting sort.

In this lesson we go over the procedure used to sort using counting sort in detail

In this lesson we follow a demo of how counting sort works and connect it to the steps mentioned in the last lesson.

In this lesson we discuss the time complexity of counting sort and cover its limitations and why we don't use counting sort so often despite it's major advantages.

In this lesson we introduce radix sort. By the end of this lesson you'll understand the odd quirks of radix sort and a detailed version of the pseudocode used to implement radix sort.

In this lesson we run through a demo of radix sort on a sample data set. By the end of this lesson you'll understand exactly how radix sort works on a set of data.

In this lesson we cover the details of how radix sort works for it's time complexity.

### Basics of Data Structures

In this lesson we cover the basics of data structures. We cover their similarities and differences between algorithms and data structures and discuss some prominent data structures in brief.

In this lesson we cover the basics of recursion and relate it to common types of problems. We discuss tail recursion and why recursion is so useful.

In this lesson we cover the details with the advantages and disadvantages of tail recursion. We also cover how to improve your recursive programs using tail recursion.

In this lesson we cover what generics are and why we need them so much for data structures. We cover how and when to create one, and explain why generics are a far superior method of storing different types of values.

### Fundamental Data Structures

In this lesson we cover how collections work. We discuss the overall structure, how they translate to most languages, and why they're so useful.

In this lesson we complete our discussion of collections. By the end of this lesson you'll be able to use collections in appropriate positions and understand the details of how collections work.

In this lesson we discuss how arraylists work under the hood and why arraylists can be superior in some cases to arrays. We also cover how they function with large sets.

In this lesson we cover the advantages and disadvantages of arraylists compared to collections and arrays. By the end of this lesson you'll understand exactly when and how to use an arraylist.

In this lesson we build linkedlists and understand how they differ under the hood compared to arraylists. We also expand on how linkedlists work under the hood and their performance compared to arraylists.

In this lesson we discuss the performance differences between linked and array lists. We cover their use cases and discuss how to use the overall function of a linkedlist best.

In this lesson we introduce the stack structure and discuss how it can be used to model real life situations. We also cover why we might want such a odd type of structure.

In this lesson we complete our discussion of stacks. We discuss the major methods we can use with stacks and how to implement a stack in your language of choice

In this lesson we introduce the queue structure which allows us to store objects in a manner similar to a real life queue. We cover how to implement one and the specially named methods. We also cover the common situations to use one.

In this lesson we cover how to implement a priority queue. We cover how a heap is the best way to store a priority queue and why a heap naturally optimizes for a queue type structure.

In this lesson we cover how to add an item to a priority queue and how it affects our algorithm and the process needed to maintain the heap property.

In this lesson we cover how to delete an item to a priority queue and how it affects our algorithm and the process needed to maintain the heap property.

In this lesson we cover how to modify a priority for an object in a priority queue to maintain the heap property. We also cover the time performance for the major dynamic operations in a priority queue.

In this lesson we cover the basics of maps. We talk about how maps are so different from the other data structures and how they can be used in many common cases, and their optimization for search time.

In this lesson we cover the 3 main types of maps. We cover how each type of map has some major advantages and disadvantages and how they differ in scope.

In this lesson we cover the map specific methods. After this lesson you will understand when to use a map and how to utilize all of its features in a program.

In this lesson we cover how sets are different from other collections. We discuss common use cases and explain how an initial capacity and load factor have a large effect on overall performance. We also have a demo of load factor.

In this lesson we cover the 3 main types of sets. We cover how each type of sets has some major advantages and disadvantages and how they differ in scope.

In this lesson we discuss the time complexity of sets. After this lesson you will understand how sets have major performance advantages over similar data structures and how to properly utilize sets.

### Trees

In this lesson we introduce the binary search tree, a data structure optimized for building trees that can be searched quickly. We discuss similarities and differences between BSTs and Heaps. We also discuss the major operations and go in detail on how finding the max/min works.

In this lesson we cover how to search a value to a Binary Search Tree. We cover the procedure and cover how it is optimized for the fastest addition not the best location always.

In this lesson we cover how to search a value to a Binary Search Tree. We cover the procedure and cover how it is often optimal to randomly add a value to a tree. We cover how adding a value can be highly dependent on the prior structure of the tree.

In this lesson we cover how to remove a value from a Binary Search Tree. We cover how we approach each type of case and discuss a demo and pseudocode for all 3 deletion types.

In this lesson we wrap-up our discussion of Binary Search trees by discussing how we can leverage BSTs in our language. We also cover the general tips we should keep in mind when dealing with a BST.

In this lesson we introduce AVL trees and explain how they differ from normal BSTs as they solve the biggest imbalance based problems in a BST.

In this lesson we discuss what a RR imbalance is and when we use a RR rotation. We cover the implantation details of RR rotation and go over a demo.

In this lesson we discuss what a RR imbalance is and when we use a RR rotation. We cover the implantation details of RR rotation and go over a demo.

In this lesson we discuss what a LR imbalance is and when we use a LR rotation. We cover the implantation details of LR rotation and go over a demo.

In this lesson we discuss what a RL imbalance is and when we use a RL rotation. We cover the implantation details of RL rotation and go over a demo.

In this lesson we cover the main tree properties of a Red-Black Tree. We cover how they achieve balance in a different way to normal AVL Trees.

In this lesson we cover rotations. We cover how we usually will only need a single left/right rotation and how they are inverses of each other. We also cover a demo and pseudocode of a left and right rotation.

In this lesson we cover how we add a value to a Red-Black Tree. We cover how the process is built based on BSTs and how we need to repair the tree after the value is added.

In this lesson we cover how to delete a value from a Red-Black Tree. We cover how a Red-Black Tree requires the deletion to take place before the fixup, and how the fixup is similar to how the addition's fixup procedure worked.

In this lesson we cover the advantages and disadvantages of AVL Trees, BST, and Red-Black Trees. We also cover other less used types of trees.

### Advanced Data Structures

In this lesson we introduce the basics of hashing. We explain how it has major performance gains and explain how we design a hashcode. We also cover why hashcodes are so important to properly generate and how the use case can define how the hashcode is calculated.

In this lesson we cover how we can achieve perfect hashing. We explain why perfect hashing is so ideal and explain various methods we can use to generate ideal hashes.

In this lesson we explain the most prominent way of dealing with collisions, chaining. We discuss how chaining is implemented and the time complexity of this process.

In this lesson we cover the more difficult form of dealing with collisions, open addressing. We discuss how open addressing requires more careful choices for the load factor and how to use the load factor.

In this lesson we introduce the basics of how graphs work and why we implement graphs in Computer Science. We also go over the major graph vocabulary needed to understand the future lessons.

In this lesson we introduce the 2 ways to store the vertices and edges; with adjacency matrices or adjacency lists. We cover how they work under the hood using a demo, and explain when to use each form.

In this lesson we go over the most important methods for Graphs in Java or other OOP languages. We cover how the graph object functions and what each of the main methods can be used for.

In this lesson we cover a BFS or Breath-First Search. We cover potential use cases, and the entire pseudocode is broken down. We then go over the processes using a demo.