Algorithms & Data Structures for Working Engineers
The Structures and Trade-offs Behind Everyday Systems
The data structures and algorithms behind everyday systems, taught through the problems they solve and measured in Python you can run. 7 modules, 35 lessons, five to nine minutes each: complexity and trade-offs, hashing, sequences, sorting and searching, trees, graphs, and the problem-solving techniques (divide and conquer, greedy, backtracking, dynamic programming) that turn a problem statement into a working algorithm.
Intermediate · 4 hours · 35 lessons · 129 labs
Who it is for
Intermediate level.
For working programmers who want to choose the right data structure and spot slow code before production does. Every idea is measured in Python you can run.
What you don't need yet:
- No computer science degree
- No heavy maths: you check each claim by measuring it
- Nothing to install: labs run in your browser
What helps:
- Everyday Python: functions, lists, dictionaries and classes
Before you start:
- Ordinary Python: functions, lists, dicts and classes (the Python course covers all of it)
Take first:
- Hands-on Python: Complete Video Course & Book — Beginner
- PCAP Certified Associate in Python Programming (PCAP-31-03) Exam Prep — Intermediate
Take next:
- Scalable System Design & Distributed Architecture — Advanced
- Apache Kafka & Event Streaming — Intermediate
Learning paths:
Nobody needs to know everything before they start. Each course builds on the one before, so a learning path takes you there step by step.
Labs
129 labs, 129 of them graded: you write the code, it runs, and graded labs check the result. The outline lists each lesson's labs.
What is free
Start free: First module free with an account. Pro: Every course, lab, handbook, practice exam and certificate.
- Pro monthly — $29 a month. Every course, lab, handbook, practice exam and certificate
- Pro yearly — $249 a year. Every course, lab, handbook, practice exam and certificate
Course outline
Complexity And Trade-offs
- Why Complexity Matters In Production (3 labs): You can explain why scanning a list grows linearly with input size while a dictionary lookup stays constant, measure both with the perf counter timer, and describe what input size n means in a complexity argument.
- Recognising The Common Growth Rates (4 labs): You can name the five common growth rates, count operations for each pattern in code, and say which code structure produces which growth rate.
- Space, In-Place Work And The Call Stack (4 labs): You can distinguish auxiliary space from in-place algorithms, measure Python object sizes with sys.getsizeof, explain why deep recursion exhausts the call stack, and convert a recursive function to an iterative one.
- Big O, Big Omega And Big Theta (3 labs): You can define big O, big Omega, and big Theta in words, verify an asymptotic claim empirically by checking the ratio of cost to n, and distinguish best, worst, and average case for linear search.
- Amortised Analysis: Why Append Is Cheap (3 labs): You can explain why appending to a dynamic array is amortised constant time by tracing the doubling strategy, compare it to fixed-increment growth, and state the credit argument for the amortised bound.
Hashing: Structure Behind Everything Fast
- What A Hash Function Promises (3 labs): You can explain the three core properties a hash function must have, implement a polynomial rolling hash, and reason about why Python randomises string hashing.
- Hash Tables: Chaining, Open Addressing And Load Factor (3 labs): You can implement a chaining hash map and a linear-probing open-addressed table, explain what the load factor measures, and identify when and why a table must resize.
- Python Dicts And Sets Under The Hood (3 labs): You can explain how Python dicts preserve insertion order, why set membership beats list membership in cost, how to implement a hashable class correctly, and what the hash-equals contract requires.
- Collisions In Practice And Hash Flooding (3 labs): You can demonstrate how a constant-return hash degrades lookup to linear time, show how anagram-based keys exploit a sum hash, and explain how per-process hash randomisation defends against flooding attacks.
- Bloom Filters: Membership Without The Data (3 labs): You can implement a Bloom filter using k hash functions derived from SHA two-fifty-six, measure its false-positive rate on a fixed word list, and explain why Bloom filters guarantee zero false negatives.
Sequences: Arrays, Lists, Stacks And Queues
- Arrays: Contiguous Memory And Constant-Time Access (4 labs): You can explain why array index access is constant time, measure the memory difference between a typed array and a list, predict the cost of front insertion versus appending, and describe why slicing produces a copy.
- Linked Lists: Nodes, Pointers And Sentinels (3 labs): You can implement a singly linked list with push-front, append, delete, and find; explain why a sentinel head eliminates edge cases; and identify workloads where a linked list outperforms a Python list.
- Stacks And Queues: Last In Or First In (4 labs): You can implement a stack using a Python list and a queue using a deque, explain the ordering discipline of each, use a stack to check balanced brackets, and measure why list.pop(0) is a poor queue implementation.
- Deques And Ring Buffers (4 labs): You can use a deque with maxlen as a sliding window, implement a ring buffer with head and tail indices and modulo wraparound, and compute a moving average over a data stream using the ring buffer.
- Choosing The Right Sequence (3 labs): You can apply five diagnostic questions to select the right sequence structure, read a performance benchmark comparing list and deque, and explain why list and deque perform similarly for a pure stack workload.
Sorting And Searching
- Comparison Sorts: Insertion, Merge And Quicksort (5 labs): You can implement insertion sort, merge sort, and quicksort with comparison counters, explain why no comparison sort beats order n log n, and demonstrate stability with tagged pairs.
- Counting And Radix Sort: Beating N Log N (4 labs): You can implement counting sort and LSD radix sort, explain when each applies, and describe the memory cost that comes with bypassing element comparisons.
- Binary Search And Its Invariant (4 labs): You can implement iterative binary search with a loop invariant, identify and fix common off-by-one errors, use the bisect module for sorted-list operations, and apply binary search to answer-space problems.
- Sorting In Real Systems: Stability, Keys And External Sort (4 labs): You can sort with key functions and tuple keys, compose sorts by chaining stable passes, and implement a k-way external merge using heapq.merge over temporary files.
- Searching With Hashes Versus Trees (4 labs): You can choose between a set, a sorted list with bisect, and a linear scan for membership and range queries, and explain when sorted order provides capabilities that hashing cannot.
Trees: Hierarchies, Search And Balance
- Binary Trees And Their Traversals (4 labs): You can build a binary tree with a node class, write recursive in-order, pre-order, and post-order traversals, implement level-order traversal with a deque, and compute height and node count.
- Binary Search Trees: Search, Insert And Delete (4 labs): You can insert and search in a binary search tree, implement all three delete cases using the in-order successor, read a sorted in-order traversal as a correctness check, and explain why sorted insertion produces a degenerate tree of linear height.
- AVL Trees: Rotations That Keep The Guarantee (4 labs): You can explain the AVL balance-factor invariant, implement single and double rotations, insert into an AVL tree with automatic rebalancing, and verify that sorted insertion keeps height logarithmic.
- B-Trees: The Structure Behind Every Database Index (4 labs): You can explain the B-tree fan-out property, implement search and split-on-insert for a minimal B-tree, print node keys by level, and compute the maximum height for a million keys given a minimum degree.
- Heaps And Priority Queues (5 labs): You can build an array-backed min-heap with sift-up and sift-down, use the heapq module for push, pop, heapify, and nlargest, implement heap sort, and model a priority queue as a task scheduler.
Graphs And Their Algorithms
- Representing A Graph: Matrix Or Adjacency List (4 labs): You can represent a graph as either an adjacency list or a two-dimensional matrix, state the memory cost of each, explain when to prefer one over the other, and encode directed and weighted edges.
- Breadth-First Search And Shortest Paths By Hops (4 labs): You can implement BFS with a deque to compute shortest hop distances and reconstruct paths, explain why BFS finds shortest paths in unweighted graphs, and use BFS to compute degrees of separation.
- Depth-First Search, Cycles And Topological Order (4 labs): You can implement recursive DFS, detect a cycle in a directed graph using colour marking, and sort a dependency graph into valid execution order using Kahn's algorithm.
- Dijkstra: Shortest Paths With A Priority Queue (3 labs): You can implement Dijkstra with a min-heap and lazy deletion, compute shortest weighted paths and their costs, explain why the greedy step fails on negative edges, and state the complexity in plain terms.
- Minimum Spanning Trees: Kruskal And Prim (4 labs): You can implement union-find with path compression and union by rank, run Kruskal's algorithm to build a minimum spanning tree edge by edge, and run Prim's algorithm from a starting vertex using a heap.
Problem-Solving Techniques
- Divide And Conquer And The Recurrence (4 labs): You can apply the split-solve-combine pattern, explain why merge sort costs order n log n using its recurrence, implement a divide-and-conquer max-subarray and compare its operation count with brute force, and identify binary search as the one-branch case.
- Greedy Algorithms: When Local Is Global (4 labs): You can implement interval scheduling by earliest finish, explain why greedy coin change fails on some coin systems by comparing with the dynamic-programming optimum, and build a Huffman code using a priority queue.
- Backtracking: Search With Pruning (3 labs): You can implement backtracking with pruning, count solutions for N-queens and compare solution counts across board sizes, measure how much pruning reduces the nodes visited versus exhaustive search, and generate permutations with a recursive generator.
- Dynamic Programming: Memoisation And Tabulation (4 labs): You can explain overlapping subproblems and optimal substructure, apply memoisation with lru_cache to avoid redundant recursion, build a bottom-up tabulation table for the knapsack problem, and reconstruct a longest common subsequence from its DP table.
- Recognising The Pattern (3 labs): You can apply a four-question decision procedure to classify an unfamiliar problem as divide-and-conquer, greedy, backtracking, or dynamic programming, implement a rule-table classifier in Python, and verify that three approaches to the same problem agree on the answer.