Each of the algorithms that we considered in seems to be an improvement over the previous in some intuitive sense, but the process is perhaps artificially smooth because we have the benefit of hindsight in looking over the development of the algorithms as they were studied by researchers over the years (see reference section). The implementations are simple and the problem is well specified, so we can evaluate the various algorithms directly by running empirical studies. Furthermore, we can validate these studies and quantify the comparative performance of these algorithms (see ). Not all the problem domains in this tutorial are as well developed as this one, and we certainly can run into complex algorithms that are difficult to compare and mathematical problems that are difficult to solve. We strive to make objective scientific judgements about the algorithms that we use, while gaining experience learning the properties of implementations running on actual data from apps or random test data.
The process is prototypical of the way that we consider various algorithms for fundamental problems throughout the tutorial. When possible, we follow the same basic steps that we took for union–find algorithms in , some of which are highlighted in this list:
The potential for spectacular performance improvements for practical problems such as those that we saw in makes algorithm design a compelling field of study; few other design activities hold the potential to reap savings factors of millions or billions, or more.
More important, as the scale of our computational power and our apps increases, the gap between a fast algorithm and a slow one grows. A new computer might be 10 times faster and be able to process 10 times as much data as an old one, but if we are using a quadratic algorithm such as quick find, the new computer will take 10 times as long on the new job as the old one took to finish the old job! This statement seems counterintuitive at first, but it is easily verified by the simple identity (10N)2/10 = 10N2, as we shall see in . As computational power increases to allow us to take on larger and larger problems, the importance of having efficient algorithms increases as well.
Developing an efficient algorithm is an intellectually satisfying activity that can have direct practical payoff. As the connectivity problem indicates, a simply stated problem can lead us to study numerous algorithms that are not only both useful and interesting, but also intricate and challenging to understand. We shall encounter many ingenious algorithms that have been developed over the years for a host of practical problems. As the scope of applicability of computational solutions to scientific and commercial problems widens, so also grows the importance of being able to apply efficient algorithms to solve known problems and of being able to develop efficient solutions to new problems.
Suppose that we use weighted quick union to process 10 times as many connections on a new computer that is 10 times as fast as an old one. How much longer would it take the new computer to finish the new job than it took the old one to finish the old job?
Answer Exercise 1.25 for the case where we use an algorithm that requires N3 instructions.