The functions we have developed so far fall into two broad categories. On one
hand, we have the category of functions that encapsulate domain knowledge.
On the other hand, we have functions that consume structures or lists. These
functions typically decompose their arguments into their immediate
structural components and then process those components. If one of the
immediate components belong to the same class of data as the input, the
function is recursive. For that reason, we refer to these functions as
<#66130#><#32769#>STRUCTURALLY (RECURSIVE) FUNCTIONS<#32769#><#66130#>. In some cases, however, we
also need functions based on <#32770#>generative recursion<#32770#>. The study of
generative recursion is as old as mathematics and is often called the study
of <#66131#><#32771#>ALGORITHMS<#32771#><#66131#>.
The inputs of an algorithm represent a <#32772#>*problem*<#32772#>. Except for rare
occasions, the problem is an instance of a large class of problems and the
algorithm works for all of these problems. In general, an algorithm
partitions a problem into other, hopefully smaller problems and solves
those. For example, a algorithm for planning a vacation trip requires
arrangements for a trip from our home to a nearby airport, a flight o an
airport near our vacation spot, and a trip from that airport to our vacation
hotel. The entire problem is solved by combining the solutions for these
problems.
Designing an algorithm distinguishes two kinds of problems: those that are
trivially solvable
and those that are not. If a given problem is trivially solvable, an
algorithm produces the matching solution. For example, the problem of
getting from our home to a nearby airport might be trivially solvable. We
can drive there, take a cab, or ask a friend to drop us off. If not, the
algorithm generates a new problem and solves those new problems. A
multistage trip is an example of a problem that is non-trivial and can be
solved by generating new, smaller problems. In a computational setting
one of the smaller problems often belongs to the same class of problems as
the original one, and it is for this reason that we call the approach
<#66133#><#32775#>GENERATIVE RECURSION<#32775#><#66133#>.
In this part of the book, we study the design of algorithms, that is,
functions based on generative recursion. From the description of the idea,
we know that this process is much more of an <#32776#>*ad hoc*<#32776#> activity than
the data-driven design of structurally recursive functions. Indeed, it is
almost better to call it inventing an algorithm than designing
one. Inventing an algorithm requires a new insight---a ``eureka.'' Sometimes
very little insight is required. For example, solving a ``problem'' might
just require the enumeration of a series of numbers. At other times,
however, it may rely on a mathematical theorem concerning numbers. Or, it
may exploit a series of mathematical results on systems of equations. To
acquire a good understanding of the design process, it is necessary to study
examples and to develop a sense for the various classes of examples. In
practice, new complex algorithms are often developed by mathematicians and
mathematical computer scientists; programmers, though, must throughly
understand the underlying ideas so that they can invent the simple
algorithms on their own and communicate with scientists about the others.
The two subsections illustrate two vastly different algorithms. The first one
is an example of something programmers invent on a daily basis. The second
one describes a fast sorting algorithm, one of the first applications of
generative recursion in computing.
<#32777#>**Terminology**<#32777#>:\ Mathematical computer scientists often do not distinguish
between structural recursion and generative recursion and refer to both
kinds of functions as algorithms. Instead they use the terminology of <#32778#>*recursive*<#32778#> and <#32779#>*iterative*<#32779#> methods. The latter refers to a subclass
of function definitions whose recursive function applications are in a
particular position in the definition. We will strictly adhere to the
terminology of algorithm and generative recursion when we
work with this class of functions because this classification matches our
thinking of design recipes better than the purely syntactic classification
of applied mathematicians.~<#66134#><#66134#>