liveBook · Manning

What you will learn in Fabulous Adventures in Data Structures and Algorithms

by Eric Lippert
Foreword by Jon Skeet

Chapter by chapter

Chapter 1: Starting a fabulous adventure

This introduction frames the book as an exploration of unusual, useful algorithms and data structures that encourage more powerful, abstract, and enjoyable ways of solving programming problems.

1.1 Defining data structures, algorithms, and complexity · 1.2 An immutable linked list · 1.2.1 Performance so far · 1.2.2 Reversing an immutable linked list · 1.3 The challenges ahead · 1.4 Summary

What you learn in chapter 1 →

Chapter 2: Immutable stacks and queues

This chapter introduces a progression from immutable linked lists to stacks, queues, undo-redo systems, mutable wrappers, and Hughes lists while comparing their performance characteristics.

2.1 Why immutability? · 2.1.1 Correctness · 2.1.2 Historical preservation · 2.1.3 Security · 2.1.4 Safer multithreading · 2.1.5 Memoization for time performance · 2.1.6 Persistence for space performance · 2.1.7 The functional programming attitude · 2.2 An immutable stack · 2.3 A covariant immutable stack · 2.4 A queue, a queue, an immutable queue · 2.5 Mutable wrappers · 2.6 Undo and redo · 2.6.1 Create an army of clones · 2.6.2 Use a different data structure and the command pattern · 2.6.3 Undo and redo with mutable-over-immutable data structures · 2.7 The Hughes list: Build it cheap, pay for it later · 2.7.1 Reverse redux · 2.7.2 Currying and partial application · 2.7.3 Implementing the Hughes list · 2.7.4 Complexity of the Hughes list · 2.7.5 Where is the data in this data structure? · 2.7.6 A couple more performance considerations · 2.7.7 Reverse a linked list · 2.8 Summary

What you learn in chapter 2 →

Chapter 3: An immutable deque

This chapter introduces immutable deques, motivates replacing naïve linked-list approaches with finger trees, and previews sublinear deque concatenation.

3.1 An immutable deque abstract data type · 3.2 A bad naïve implementation · 3.3 A finger tree · 3.3.1 The mini-deque · 3.3.2 A new definition of a deque · 3.4 Visualizing the data structure · 3.5 Amortized performance of the deque · 3.6 Are we abusing the type system? · 3.7 Concatenation of deques · 3.8 Performance after adding concatenation · 3.9 Why is this tree called a finger tree? · 3.10 Summary

What you learn in chapter 3 →

Chapter 4: Memoizing immutable quadtrees to make a better Life

This chapter introduces Conway’s Game of Life as a vehicle for comparing incremental optimization with a frame-changing HashLife approach built from immutable quadtrees and memoization.

4.1 The rules of Life · 4.2 A typical first attempt · 4.2.1 Performance of the naïve implementation · 4.2.2 Same algorithm, better constant factor · 4.2.3 Improving the algorithm with change tracking · 4.3 An immutable quadtree · 4.3.1 The IQuad interface · 4.3.2 Implementing the 0-quad leaf cells · 4.3.3 A strategy for compressing space · 4.3.4 A general-purpose memoizer · 4.3.5 A memoized quadtree implementation · 4.3.6 Indexing an immutable quadtree like an array · 4.3.7 A few more helpful extension methods · 4.4 The HashLife algorithm · 4.4.1 The base case: Stepping a 2-quad produces a 1-quad · 4.4.2 A first attempt at a recursive algorithm · 4.4.3 The grid always shrinks · 4.4.4 Is this algorithm inefficient? · 4.4.5 Take bigger steps forward · 4.4.6 Putting it all together · 4.5 Summary

What you learn in chapter 4 →

Chapter 5: What’s up with you, Directed Acyclic Word Graph?

This chapter introduces the problem of storing and quickly searching large word lists, and previews a progression from sorted lists to tries and DAWGs.

5.1 Two problems, two weak solutions · 5.1.1 Hash sets are a nonsolution · 5.1.2 Sorted lists are… fine? · 5.2 The prefix tree · 5.2.1 Nodes and edges · 5.2.2 The trie-building algorithm · 5.2.3 Using a trie as a word list · 5.2.4 How much memory are we saving with a trie? · 5.3 Tries are not-so-secretly finite state automata · 5.4 Building a DAWG · 5.4.1 What problems must we solve to build a DAWG? · 5.4.2 Equivalence of nodes · 5.4.3 The DAWG-building algorithm · 5.4.4 How much expense does optimizing the graph as you go add? · 5.5 DAWG vs. trie for ENABLE · 5.6 Summary

What you learn in chapter 5 →

Chapter 6: Combinatorial algorithms

This chapter introduces algorithms for generating Cartesian products, permutations, and combinations of sequences, and relates their ordered outputs to representations of integers.

6.1 The Cartesian product · 6.1.1 The Cartesian product of a few sets or sequences · 6.1.2 The Cartesian product of arbitrarily many sequences · 6.1.3 The connection to the integers · 6.2 Permutations · 6.2.1 Lexicographic permutations with repetitions · 6.2.2 The factorial base representation of permutation numbers · 6.2.3 The Fisher–Yates shuffling algorithm · 6.2.4 A recursive change-ringing algorithm · 6.2.5 Even’s change-ringing algorithm · 6.3 Combinations · 6.3.1 Lexicographic combinations with a twist · 6.3.2 Counting combinations · 6.3.3 The combinatorial base representation of combinations · 6.4 Summary

What you learn in chapter 6 →

Chapter 7: First abstract nonsense interlude: Category theory

This introduction motivates category theory as a practical, theoretical, and enjoyable way to reason about abstractions and composable operations in programming, and previews its connection to type-system variance.

7.1 Category theory is generalized abstract nonsense · 7.2 Covariant endofunctors in the category of types · 7.3 Contravariant endofunctors in the category of types · 7.4 Summary

What you learn in chapter 7 →

Chapter 8: Coloring graphs with backtracking search

Introduces graph coloring as an adjacency-constrained assignment problem and previews using immutable data structures and backtracking search to solve it and related problems.

8.1 Coloring South America · 8.2 An immutable multidictionary · 8.3 An immutable undirected graph · 8.4 Coloring simple graphs · 8.5 Solving Sudokus with backtracking search · 8.5.1 Graph coloring is NP-complete · 8.5.2 Implementing a general backtracker · 8.5.3 How could we improve? · 8.5.4 Backtracking and the Cartesian product · 8.6 Scheduling problems are graph-coloring problems · 8.7 Summary

What you learn in chapter 8 →

Chapter 9: Greedy iterative pretty printing

This chapter introduction frames automatic code formatting as a pretty-printing problem and previews a fast nonrecursive greedy solution and its parse-tree transformation design.

9.1 The pretty-printing problem · 9.2 Greedy algorithms and making change · 9.3 A greedy pretty-printing algorithm · 9.3.1 The doc data structure · 9.3.2 Visualizing a doc: How deep does it get? · 9.3.3 Phase 2: Implementing Fits() without recursion · 9.3.4 Phase 2 continued: Implementing Pretty() without recursion · 9.4 Phase 1: Transforming parse trees with the visitor pattern · 9.4.1 Implementing the visitor pattern · 9.4.2 From parse tree to doc · 9.5 Summary

What you learn in chapter 9 →

Chapter 10: Unification and anti-unification

This chapter introduces unification as filling holes to make structures equal and anti-unification as replacing differences with holes to find shared generalizations.

10.1 Unifying binary terms · 10.1.1 Unifying binary terms, first attempt · 10.1.2 Unifying binary terms, this time with an occurs check · 10.2 The performance of binary term unification · 10.3 Type inference and logic programming · 10.4 Anti-unifying binary terms · 10.5 The first-order binary-term anti-unification algorithm · 10.6 Clone detection and fix deduction · 10.7 Summary

What you learn in chapter 10 →

Chapter 11: Second abstract nonsense interlude: Monads

This chapter introduction frames monads as common patterns for adding capabilities to existing types and structuring programs as chained workflows.

11.1 What’s the value for OO programmers? · 11.2 How hard can it be to divide by 2? · 11.3 Generalizing to arbitrary functions with Map and Bind · 11.4 The sequence monad is an additive monad · 11.5 Summary

What you learn in chapter 11 →

Chapter 12: A better abstraction for randomness

This chapter introduces a higher-level abstraction for discrete randomness, centered on representing and efficiently sampling unfair die rolls as categorical distributions in preparation for Bayesian reasoning.

12.1 What are probabilities? · 12.2 What are discrete probability distributions? · 12.3 Generating uniform samples with Random · 12.4 IDistribution<T> and IDiscreteDistribution<T> · 12.5 Flipping an unfair coin with Bernoulli · 12.6 Improving the ecosystem with extension methods · 12.7 Representing unfair die rolls by adding a projection · 12.8 Categorical algorithm 1: Make a big list · 12.9 Categorical algorithm 2: Climb a ladder · 12.10 Categorical algorithm 3: Rejecting rejection sampling · 12.11 Categorical algorithm 4: The alias algorithm · 12.12 Filtering out a category · 12.13 Summary

What you learn in chapter 12 →

Chapter 13: Conditional probability with Bayes’ theorem

This chapter introduces using Bayes’ theorem with discrete probability distributions to update prior beliefs from observations and reason from effects back to likely causes.

13.1 Bayes’ theorem · 13.2 Likelihood functions and joint distributions · 13.3 Updating priors by reasoning from effects to causes · 13.4 Some applications of Bayesian reasoning · 13.5 Unconditional likelihood functions are independent · 13.6 Summary

What you learn in chapter 13 →

Chapter 14: Third abstract nonsense interlude: The probability monad

This chapter introduction frames discrete probability distributions as another monad that lifts ordinary value workflows into workflows over random values.

14.1 The requirements for a monad · 14.2 Probability distributions as additive monads · 14.3 A critique · 14.4 Summary

What you learn in chapter 14 →

Chapter 15: Sampling continuous distributions

This chapter introduction positions the next two chapters as extending sampling and Bayesian reasoning from categorical distributions to one-dimensional continuous distributions, with this chapter focusing on sampling techniques.

15.1 What is a continuous probability distribution? · 15.2 Sampling the continuous uniform distribution · 15.3 Sampling the normal distribution · 15.4 The inverse transform method · 15.5 Rejection sampling · 15.5.1 Clamping with rejection sampling · 15.5.2 Problems with rejection sampling · 15.6 Summary

What you learn in chapter 15 →

Chapter 16: Markov processes and the Metropolis algorithm

This chapter introduces Markov processes and uses them as the foundation for Metropolis sampling of continuous posterior distributions.

16.1 What is a Markov process? · 16.2 Markov texts · 16.3 Computing posteriors of continuous distributions · 16.4 The Metropolis algorithm · 16.5 Sampling posteriors with Metropolis · 16.6 Summary

What you learn in chapter 16 →

Concepts explained in this book

These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.