There is an important class of calculations that can be implemented with recursive algorithms. A standard example is the factorial function n!, which is defined for non-negative integer values of n and which is equal to n·(n − 1)·(n − 2)… (1). For example, 5!=5·4·3·2·1=120. This function can be defined as:
n! = 1 for n = 1 or n = 0 n! = n·(n − 1)! for n > 1
This is a recursive definition, in which n! is defined in terms of (n − 1)!.
Like other modern programming languages, JavaScript supports recursive functions—
functions that call themselves. Document 6.8 demonstrates a recursive function that calculates n!.
Document 6.8 (factorial2.htm)
<html>
<title>Calculate n!</title>
<body>
<script language="JavaScript" type="text/javascript">
function nFactorial(n) {
if (n<=1) return 1;
else return n*nFactorial(n-1);
</script>}
</head>
<h1>Calculate n factorial (n!)</h1>
<p>
<form>
Table 6.2 Summary of some event handlers used in forms Event handler Action
onblur Initiates action when a user tabs from a form field or clicks elsewhere in a document.
onchange Initiates action when a user changes the contents of a form field.
onclick Initiates action when a user clicks on form input field.
onfocus Initiates action when a user tabs to or clicks on a form field.
onload Inside a <body> tag, initiates action when a document is loaded into the user’s browser.
151 6.5 Recursive Functions
Enter n (a non-negative integer):
<input type="text" name="n" size="2" maxlength="3"
value="0"
onblur="factorial.value=
nFactorial(parseInt(n.value,10));" />
(Press Tab to get n!.)<br>
<input type="text" name="factorial" size="10"
maxlength="11" value="1" /> <br />
</form>
</body>
</html>
The shaded line contains the critical code, in which the function
The success of recursive functions depends on the function model discussed at the beginning of this chapter, in which information flows into a function through the parameter call plus the three recursive calls add a total of four plates to the stack. At the third recur-sive call, n = 1 and a value of 1 is returned. Executing a return statement is equivalent to removing one of the plates. Subsequently, the three remaining plates are removed as the
Table 6.3 Calculating 4! using a recursive algorithm
Local value of n Action Value returned
n = 4 Initial call Deferred
n = 3 First recursive call Deferred
n = 2 Second recursive call Deferred
n = 1 Third recursive call 1
n = 2 Complete multiplication 2·1 2
n = 3 Complete multiplication 3·2 6
n = 4 Complete multiplication 4·6 24
152 6 JavaScript Functions
6
deferred multiplications are carried out and a value is returned. When the function returns control of the script back to the point from which it was initially called, all the “plates”have been removed from the stack.
For more complicated recursive algorithms, it can be difficult to actually follow the course of the calculations. Fortunately, it isn’t necessary to do this. As long as the algo-rithm is properly designed, with a condition that will eventually terminate the recursive calls, the programming environment takes care of keeping track of all the intermediate values generated during the execution of the algorithm.
Here’s another example of a well-known function that is defined recursively. The Fibonacci numbers Fn that form the sequence 1, 1, 2, 3, 5, 8, 13, 21, … are defined for positive integer values of n as
Fn = 1 if n = 1 or n = 2 Fn = Fn − 1 + Fn − 2 if n > 2
Document 6.9 shows how simple it is to evaluate this function using a recursive algorithm.
Document 6.9 (fibonacci.htm)
<html>
<title>Calculate Fibonacci numbers</title>
<body>
<script language="JavaScript" type="text/javascript">
function Fib(n) { if (n<=2) return 1;
else return Fib(n-1)+Fib(n-2);
</script>}
</head>
<h1>Calculate the n<sup>th</sup> Fibonacci number</h1>
<p>
<form>
Enter n (a positive integer):
<input type="text" name="n" size="2" maxlength="3"
value="1"
onblur="FibN.value=Fib(parseInt(n.value));" />
(Press Tab to get n<sup>th</sup>
Fibonacci number.)<br>
<input type="text" name="FibN" size="8"
maxlength="8" value="1" />
</form>
</body>
</html>
153 6.5 Recursive Functions
Because this function requires multiple recursive calls, it is not easy to follow the sequence of events. However, you don’t have to worry about these details as long as the algorithm is written properly!
Recursive algorithms can also be formulated using count-controlled or conditional loop structures. However, a recursive formulation is often much shorter and more direct to implement in code. The famous “Towers of Hanoi” problem is an excellent example of a problem that is difficult to solve “directly” but is trivial to solve recursively.
Consider three poles, on one of which are stacked 64 golden rings. The bottom ring is the largest and the others decrease in size. The object is to move the 64 rings from one pole to another, using the remaining pole as a temporary storage place for rings. There are two rules for moving rings:
1. Only one ring can be moved at a time.
2. A ring can never be placed on top of a smaller ring.
Describe how to move the entire stack of rings from one pole to another.
It can be shown that it will take 2n − 1 moves to move n rings. For n = 64, if you could move one ring per second without ever making a mistake, it would take roughly 100 times the estimated age of the universe! However, you can develop an algorithm that will work, in principle, for any number of rings and apply it to a value of n that is small enough to be practical. For n = 4, it will take 15 moves.
In a conceptual sense, the solution is easy (but perhaps not obvious). Suppose the poles are labeled A, B, and C. Initially, all the rings are on A and the goal is to move them all to C. The steps are:
1. Move n − 1 rings from A to B.
2. Move the nth ring from A to C.
3. Move n − 1 rings from B to C.
This solution is “conceptual” in the sense that it has not yet been specified how to do steps 1 and 3; only step 2 defines a specific action that can be taken. However, the power of recursive functions allows this problem to be solved without giving additional specific steps! Consider Document 6.10.
154 6 JavaScript Functions
6
Document 6.10 (towers.htm)<html>
<head>
<title></title>
<script language="javascript" type="text/javascript">
function move(n,start,end,intermediate) { if (n > "0") {
move(n-1,start,intermediate,end);
document.write("move ring "+n+
" from "+start+" to "+end+".<br />");
move(n-1,intermediate,end,start);
}}
var n=prompt("Give n:");
move(n,"A","C","B");
The success of this algorithm depends, once again, on how parameter lists work—
passing information along a “one-way street” into a function. In principle, you can manu-ally follow the individual values of the parameters during the recursive calls, but it is hardly worth the effort. All that is actually required is that the algorithm be stated appropriately.