• Aucun résultat trouvé

Recursive Functions

Dans le document Guide to HTML, JavaScript and PHP (Page 165-169)

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.

6.6

Dans le document Guide to HTML, JavaScript and PHP (Page 165-169)