Supplemental files and examples for this book can be found at http://examples.oreilly.com/9780596516246/. Please use a standard desktop web browser to access these files, as they may not be accessible from all ereader devices.
All code files or examples referenced in the book will be available online. For physical books that ship with an accompanying disc, whenever possible, weve posted all CD/DVD content. Note that while we provide as much of the media content as we are able via free download, we are sometimes limited by licensing restrictions. Please direct any questions or concerns to .
Preface
As Trinity states in the movie The Matrix :
It's the question that drives us, Neo. It's the question that brought you here .
You know the question, just as I did .
As authors of this book, we answer the question that has led you here:
Can I use algorithm X to solve my problem? If so, how do I implement it?
You likely do not need to understand the reasons why an algorithm is correctif you do, turn to other sources, such as the 1,180-page bible on algorithms, Introduction to Algorithms , Second Edition, by Thomas H. Cormen et al. (2001). There you will find lemmas, theorems, and proofs; you will find exercises and step-by-step examples showing the algorithms as they perform. Perhaps surprisingly, however, you will not find any real code, only fragments of "pseudocode," the device used by countless educational textbooks to present a high-level description of algorithms. These educational textbooks are important within the classroom, yet they fail the software practitioner because they assume it will be straightforward to develop real code from pseudocode fragments.
We intend this book to be used frequently by experienced programmers looking for appropriate solutions to their problems. Here you will find solutions to the problems you must overcome as a programmer every day. You will learn what decisions lead to an improved performance of key algorithms that are essential for the success of your software applications. You will find real code that can be adapted to your needs and solution methods that you can learn.
All algorithms are fully implemented with test suites that validate the correct implementation of the algorithms. The code is fully documented and available as a code repository addendum to this book. We rigorously followed a set of principles as we designed, implemented, and wrote this book. If these principles are meaningful to you, then you will find this book useful.
Principle: Use Real Code, Not Pseudocode
What is a practitioner to do with 's description of the Ford-Fulkerson algorithm for computing maximum network flow?
Figure 1. Example of pseudocode commonly found in textbooks
The algorithm description in this figure comes from Wikipedia ( to see our code listing by comparison. We use only documented, well-designed code to describe the algorithms. Use the code we provide as-is, or include its logic in your own programming language and software system.
Some algorithm textbooks do have full real-code solutions in C or Java. Often the purpose of these textbooks is to either teach the language to a beginner or to explain how to implement abstract data types. Additionally, to include code listings within the narrow confines of a textbook page, authors routinely omit documentation and error handling, or use shortcuts never used in practice. We believe programmers can learn much from documented, well-designed code, which is why we dedicated so much effort to develop actual solutions for our algorithms.
Principle: Separate the Algorithm from the Problem Being Solved
It is hard to show the implementation for an algorithm "in the general sense" without also involving details of the specific solution. We are critical of books that show a full implementation of an algorithm yet allow the details of the specific problem to become so intertwined with the code for the generic problem that it is hard to identify the structure of the original algorithm. Even worse, many available implementations rely on sets of arrays for storing information in a way that is "simpler" to code but harder to understand. Too often, the reader will understand the concept from the supplementary text but be unable to implement it!
In our approach, we design each implementation to separate the generic algorithm from the specific problem. In , for example, when we describe the A*Search algorithm, we use an example such as the 8-puzzle (a sliding tile puzzle with tiles numbered 18 in a three-by-three grid). The implementation of A*Search depends only on a set of well-defined interfaces. The details of the specific 8-puzzle problem are encapsulated cleanly within classes that implement these interfaces.
We use numerous programming languages in this book and follow a strict design methodology to ensure that the code is readable and the solutions are efficient. Because of our software engineering background, it was second nature to design clear interfaces between the general algorithms and the domain-specific solutions. Coding in this way produces software that is easy to test, maintain, and expand to solve the problems at hand. One added benefit is that the modern audience can more easily read and understand the resulting descriptions of the algorithms. For select algorithms, we show how to convert the readable and efficient code that we produced into highly optimized (though less readable) code with improved performance. After all, the only time that optimization should be done is when the problem has been solved and the client demands faster code. Even then it is worth listening to C. A. R. Hoare, who stated, "Premature optimization is the root of all evil."
Principle: Introduce Just Enough Mathematics
Many treatments of algorithms focus nearly exclusively on proving the correctness of the algorithm and explaining only at a high level its details. Our focus is always on showing how the algorithm is to be implemented in practice. To this end, we only introduce the mathematics needed to understand the data structures and the control flow of the solutions.
For example, one needs to understand the properties of sets and binary trees for many algorithms. At the same time, however, there is no need to include a proof by induction on the height of a binary tree to explain how a red-black binary tree is balanced; read Chapter 13 in (Cormen et al., 2001) if you want those details. We explain the results as needed, and refer the reader to other sources to understand how to prove these results mathematically.
In this book you will learn the key terms and analytic techniques to differentiate algorithm behavior based on the data structures used and the desired functionality.
Principle: Support Mathematical Analysis Empirically
We mathematically analyze the performance of each algorithm in this book to help programmers understand the conditions under which each algorithm performs at its best. We provide live code examples, and in the accompanying code repository there are numerous JUnit (http://sourceforge.net/projects/junit) test cases to document the proper implementation of each algorithm. We generate benchmark performance data to provide empirical evidence regarding the performance of each algorithm.