In today’s world, computers are ubiquitous, finding a place in almost all spheres of everyday human life. The primary task of computers is to execute programs and produce some meaningful and useful output. For these programs to execute rapidly, it is not just the hardware that is used by the computers, but also the algorithms embedded in the programs that play a crucial role. This book focuses on algorithms, and is intended to be a textbook for undergraduates. The required background has not been mentioned, but some knowledge of discrete mathematics, data structures, and programming should be adequate. The book originated from lecture notes developed by the three authors. The emphasis is not on formal proofs, but on mathematical ideas. Every chapter includes numerous exercises, but they have not been rated in terms of difficulty. Moreover, no solutions manual has been provided.

The book is made up of 11 chapters, including one that is a prologue. The authors divide the book into four logical parts. The first part, containing chapters 1 and 2, includes the RSA cryptosystem and divide-and-conquer algorithms for integer multiplication, sorting and median finding, and the fast Fourier transform. The second part, including chapters 3, 4 and 5, looks at data structures and graphs. The third part, chapters 6 and 7, looks at dynamic programming and linear programming. The fourth part looks at ways of tackling hard problems. The theory of nondeterministic polynomial time (NP) completeness, heuristics, and quantum algorithms are described in this part, which contains chapters 8, 9, and 10.

There are numerous introductory books on algorithms. This book is special in that there are not many books that place emphasis on general algorithm design principles with regard to divide-and-conquer, greedy algorithms, dynamic programming, backtracking, and branch-and-bound. In this book, the authors discuss these topics, but fail to mention that they are fundamental design principles. Students who are new to the field of algorithms should be made aware of this classification. The discussion pertaining to the last two design techniques is not satisfactory. The two important techniques are covered in just five pages. The application of branch-and-bound for solving integer linear programming problems could have been mentioned.

The discussion related to NP-complete problems is not illuminating in a few places. For example, the authors could have better explained decision problems, search problems, and optimization problems. On page 245, the authors write that “nobody believes that FACTORING is NP-complete,” without giving any hint to the student as to why this is so. On page 278, it is mentioned that “we already know the VERTEX COVER problem is NP-hard.” Succeeding pages also mention NP-hard problems. I searched the index, but did not find any mention of “NP-hard.” I then searched the entire book, but did not find any definition for the term “NP-hard.” I wonder how the three authors failed to define NP-hard problems, and to distinguish between NP-hard and NP-complete problems. Even those who provided feedback or beta tested the drafts of the book seem to have overlooked this. The discussion on reductions could have been on traditional lines, explaining and distinguishing Karp reducibility and Cook reducibility. The inclusion of linear programming seems unusual, despite its practical value.

It is anyone’s guess whether every useful algorithm will ultimately be implemented in a computer program using a specific programming language. Nevertheless, this book pays scant attention to implementation aspects and pitfalls. There is inadequate discussion about tools (summations, probability) and methods for analyzing algorithms, models of computation, tradeoffs (for example, between time and space), running times (amortized, probabilistic, expected case, worst case), proof of correctness, real-world applications of algorithms, comparison of algorithms, and advantages and disadvantages of various algorithm design principles and their applicability to problems. The coverage and treatment of material in the book should have been deeper. Although the authors state that students appreciate mathematical ideas more than formal proofs, it may be argued that undergraduates should be introduced to formalism at the early stages. Fortunately, this book does not do away with formal proofs completely.

The book contains more material than can be covered in a one-semester course. Ideally, there should be two courses: one on algorithms and another on complexity. The exercises in the book are plentiful and stimulating. The inclusion of quantum algorithms is welcome. Shortcomings aside, I recommend this book as a supplementary textbook, after having tested it in a course.