
This course includes our updated coding exercises so you can practice your skills as you learn.
See a demo
Explore abstract data types and data structures, clarifying how an abstract data type defines behavior and a data structure provides implementation, using a stack with push, pop, and peek.
Explore the definition of an algorithm, its input-output transformation, and the formal steps that produce correct results, using sorting and insertion sort examples described in pseudocode.
Explore time complexity of a brute-force zero-sum triplet counter using nested loops, reading integers from files, and benchmarking how running time scales non-linearly with input size.
Build a log-log plot to predict running time from input size, using log base two, derive t(n) = a n^3, and validate with experimental data.
Explore approximations and order of growth by trimming insignificant terms with tilt approximation, focusing on frequency of statement execution and how constants and high-order terms shape running time estimates.
Explore order of growth from exponential to logarithmic, including cubic, quadratic, linear, and linearithmic time, and review worst-case big O guarantees.
Discover the basics of arrays in C#, including initialization, zero-based indexing, and length; explore memory layout, resize limits, and multi-dimensional and jagged arrays, plus array class utilities.
Explore how arrays are laid out in memory as reference types, with heap data and stack references, including contiguity and constant-time access, and how 32-bit versus 64-bit pointers differ.
Explore the time complexities of common array operations, including access by index, search, add, insert, update, and remove, and see how resizing and copying affect performance.
Explore bubble sort theory with animated demonstrations, tracking i and j and the wall that divides sorted and unsorted parts, and learn its in-place, stable, quadratic time limitations.
Implement a bubble sort in C# with a swap helper and a decreasing wall, and validate results using unit tests in dotnet and NUnit.
Explain how stable sorts preserve the relative order of duplicates, with bubble sort as a stable example, and how a tiny change can render a sort unstable.
See how selection sort selects the largest element each pass and swaps it into place, an in-place, unstable, quadratic-time algorithm that sorts an unsorted array using a wall and iterator.
Implement selection sort in C# by tracking the largest element each pass and swapping it with the unsorted portion. Validate with unit tests and note the quadratic time complexity.
Insertion sort partitions the array with a wall, inserting each unsorted value into the sorted left side by shifting elements, an in-place and stable algorithm with quadratic time.
Demonstrates implementing insertion sort in a C# sorting class with a static void method, shifting elements to insert each unsorted item, and unit testing to verify sorted results.
Explore recursion by tracing a recursive factorial and its base case, compare it with an iterative version, and understand stack overflow and recursion depth limits.
Extend shell sort by pre sorting with gaps, starting large and reducing to one. Recognize that it is in place and unstable, with performance depending on the gap sequence.
Implement shell sort for an integer array by a generalized insertion sort using a gap sequence, with outer and inner loops and swaps, and verify with unit tests.
Explore merge sort, a divide-and-conquer sort algorithm, and follow its splitting and merging phases using an auxiliary array. Understand its stability, not in place nature, and base two time complexity.
Implement a merge sort in C# with local functions inside the merge sort method, including sorting, merging, an auxiliary array, and a unit test.
Explore quicksort theory, a divide-and-conquer, in-place recursive algorithm using a pivot to partition elements, with average O(n log n) time and worst-case O(n^2).
Explore quicksort in C#: implement a recursive quicksort with a partition method, using low and high boundaries, a first-element pivot, i and j pointers, swaps, and base-case termination.
Explore the built-in list in .net, showing how it uses an internal array, tracks count and capacity, resizes, and supports operations like sort, binary search, reverse, and read-only views.
Explore linked lists by treating a node as the basic building block that stores data and points to the next node, then implement a Node class and iterate the chain.
Explore linked lists as an abstract data type, detailing head and tail references, core operations (add, remove, find, enumerate), and the differences between singly and doubly linked lists.
Examine the singly linked list and its adding operations to the front and tail with head and tail pointers, and removing first or last, noting constant and linear time behavior.
Learn to implement a generic singly linked list in C# with add first, add last, remove first, remove last, including head, tail, count, and unit tests.
Compare singly and doubly linked lists: the latter uses two references, next and previous, enabling constant-time removal of the last node, and invites considerations of circular variants and memory trade-offs.
Explore the built-in doubly linked circular list in the BCL, detailing head and tail references, node structure, and constant-time insertions at ends or before/after a node.
Explore the theory of stacks as an abstract data type, a last in, first out structure with push, pop, and peak; compare array versus linked list backing.
Implement a generic array stack in C# with push, peak, and pop; expose is empty and count; and support enumeration via IEnumerable<T> and yield return, guided by tests and TDD.
Implement a linked stack backed by a singly linked list, with push, pop, peek, and count guarded by empty checks. Include unit tests and an enumerable interface demonstration.
Explore the built-in dotnet stack from system.collections.generic, its array-backed design, and operations like push, pop, and peek, with constant time for peek and pop and linear time for resizing.
Explore how a queue enforces first in, first out with enqueue, dequeue, and peek, compare array and linked list backings, and understand memory issues and efficient slot usage.
Explore how to implement a queue based on an array using generics, with head and tail, enqueue and dequeue operations, and dynamic resizing when full.
Implement a circular queue by wrapping the tail to the array start, improving memory use. Manage wrapped states, copy elements in order, and unwrap by doubling the array when needed.
Implement a circular queue in C# with a generic type, backed by an array, supporting enqueue, dequeue, peek, and enumeration. Manage wrapping, dynamic resizing, and track head, tail, and count.
Implement a queue with a singly linked list, delegating enqueue to add last, dequeue to remove first, and peek to read the head, with guard clauses.
Learn how the built-in queue in the .NET BCL uses a circular array, doubles capacity on resize, and offers enqueue, dequeue, peek, contains, and clear with varying time costs.
Explore linear search by iterating arrays and lists to find elements, implement exists and index of, compare lists with linq methods like find, where, and all, and discuss time complexity.
Binary search divides a sorted array in halves, compares the middle element, and continues in the left or right half to locate the target in log n steps.
Implement binary search in C#, iteratively and recursively, returning the index or -1, and keep the input sorted for fast lookups with insertion sort for new elements.
Explore symbol tables, or dictionaries in Dotnet, using key-value pairs for fast insertion and retrieval. Examine four implementations—linked list, parallel arrays, balanced binary tree, and hash table.
Explore API of symbol tables, comparing ordered and unordered variants, and implement operations such as add, get and try-get, lazy removal, remove, contains, min, max, floor, ceiling, rank, and select.
Study a simple symbol table built on a linked list with generic key-value pairs; implement try-get, add, contains, and keys, and discuss linear search performance.
Implement remove method for a sequential search symbol table, ensuring non-null keys and no lazy removal, adjusting counter, removing the key-value pair fully, and returning true if found, false otherwise.
Implement the remove method for a singly linked list, guarding with argument null exception on a null key, and update first, current, and previous references to return true when removed.
Explore a binary search based symbol table using two parallel arrays for keys and values, with rank, get value or default, add, remove, and capacity resizing.
Implement methods based on key ordering for a binary search-based symbol table, covering min, max, remove min, remove max, select by index, sailing, floor, and range queries.
Implement min, max, remove, select, sailing and floor in a binary search based symbol table, using rank for range queries and guarding null keys.
Explore how symbol tables enable fast key-based data retrieval, comparing ordered and unordered forms and why binary search symbol tables trade log n search time for linear insertion.
Why learn about data structures and algorithms?
Algorithms and data structures constitute the fundamentals of programming.
Good understanding of algorithms and data structures is one of the most important requirements for a great number of work positions. You'll have to solve many problems related to algorithms and data structures at coding interviews. Indeed, you can live without an understanding of algorithms and data structures, in general. However, you can do that until you face a real problem which requires to choose right data structures and implement custom algorithms. If you haven't ever faced such problems, believe me, this is just a matter of time. One day, you'll face such a problem and if you don't understand algorithms and data structures in depth, you'll feel yourself ashamed and helpless. You'll be stuck.
If you're not good at algorithms and data structures, you'll never pass a coding interview in a decent company. Almost all the companies prefer to hire those developers who have good understanding of algorithms and data structures, remember that. Do not delay the study of fundamental concepts.
Better hardware is not a solution for all the performance-related problems. Sometimes, you need to write software for very slow devices. And that very often depends on the budget of a customer, by the way, so you don't have a control over it.
You'd better to understand what's going on under the hood at least one level in-depth. Indeed, if you don't understand how List works, sometimes you'll make sub-optimal or completely wrong decisions.
Why this course?
You may ask me "why should I take exactly your course?" And here is my answer:
This course is a comprehensive tutorial which covers a great number of topics
I tried to do my best to make this course not dry
This course concentrates not only at algorithms and data structures in general but it uncovers the internals of data structures and algorithms built-in .NET BCL (.NET Core's BCL is the same regarding fundamental data structures and algorithms)
This course is practical with exercises and solutions
This course will definitely help you to pass technical interviews
This course is made by a professional software developer with more than 10 years of real-world experience
and many other reasons :)
What's in the Course?
For now, the course covers:
Introduction to Algorithms and Data Structures: what is a data structure, abstract data type and what's the difference between these notions. What is an algorithm and why they are important to us?
Introduction to Algorithm Analysis: determine how long will a program work, build a log-log plot, approximations, order of growth (Big-O notation), memory consumption
Arrays: arrays in C#, arrays in memory, time complexity of operations on arrays
Sort Algorithms: bubble sort, selection sort, insertion sort, recursion, shell sort, merge sort, quick sort, stability of sort algorithms
Lists: List built-in .NET BCL, nodes, linked list including singly and doubly linked lists, linked list built-in .NET
Stacks: theory and practice; stack based on array, stack based on a linked list, stack built-in .NET
Queues: theory and practice; queue based on array, circular queue, queue based on linked list, queue built-in .NET BCL
Search Algorithms: linear search, binary search (more will be added in the future)
Symbol Tables: intro, API, sequential search-based, binary search-based
Hash Tables: intro, hash functions, GetHashCode, approaches to collisions resolving: separate chaining and linear probing, Dictionary built-in BCL, Sets in BCL
Trees: binary search tree (BST), implementing BST (more will be added in the future)
Heaps: intro, heaps and arrays, implementation, Heap Sort (more will be added in the future, specifically about Priority Queues)
Immutable Collections: immutability and memory pressure, immutable stacks and queues, immutable list, immutable sets, immutable dictionaries, builders in immutable collections
Different Algorithms. This section will include different algorithms as you might guess. For now it convers the Sieve of Eratosthenes.
Take this course now and you'll be satisfied! Don't forget that Udemy provides 30-day money back refund policy, so if you don't like the course, you just click on a couple of buttons and get your money back!