Sie sind auf Seite 1von 55

RECURSION

"Normally", we have methods that call other methods. For example, the main() method calls the square() method.

What is recursion?
Recursive Method: A recursive method is a method that calls itself.

a function calls itself

direct recursion indirect recursion f1 f f2

a function calls its invoker

Simple Example

public class Recursion { public static void main (String args[]) { count(0); This program simply System.out.println(); } counts from 0-2: public static void count (int index) 012 { System.out.print(index); if (index < 2) count(index+1); } }

Recursion
is an alternative to iteration (loop)
often more "elegant" and concise than a loop sometimes very inefficient

Recursive definitions are used primarily to define infinite sets. When defining such as set, giving a complete list of elements is impossible, and for large finite sets, it is inefficient.

Recursive programs typically use a large amount of computer memory and the greater the recursion, the more memory used. Recursive programs can be confusing to develop and extremely complicated to debug.

A recursive definition consists of 2 parts : In the first part, called the anchor or ground case the basic elements that are building blocks of all other elements of the set are listed. In the second part, rules are given that allow for the construction of new objects out of basic elements or objects that have already been constructed.

These rules are applied again and again to generate new objects. Example : To construct the set of natural numbers, one basic element, 0, is singled out, and the operation of incrementing by 1 is given as : 0 N; if n N, then (n+1) N; there are no other objects in the set N. N consists of the following items : 0,1,2,3,4,5,6,7,9

Recursive Definitions serve two purposes: Generating new elements Testing whether an element belongs to a set. Recursive definitions are frequently used to define functions and sequence of numbers.

How Recursion Handle

A recursive function call is handled like any other function call Each recursive call has an activation record on the stack

stores values of parameters and local variables

When base case is reached return is made to previous call

the recursion unwinds

To understand how recursion works, it helps to visualize what s going on. To help visualize, we will use a common concept called the Stack. A stack basically operates like a container of trays in a cafeteria. It has only two operations: Push: you can push something onto the stack. Pop: you can pop something off the top of the stack.

Each time a method is called, you push the method on the stack. Save the position in the calling method Push the called method s activation frame on the stack Begin execution of the called method

Each time the method returns or exits, you pop the method off the stack. Pop the current method off the stack Continue execution of the method which called it If a method calls itself recursively, you just push another copy of the method onto the stack. We therefore have a simple way to visualize how recursion really works.

public class Recursion1V0 { public static void main (String args[]) { count(0); System.out.println(); } public static void count (int index) { System.out.print(index); if (index < 2) count(index+1); } }

Recursive algorithm
An algorithm that finds the solution to a given problem by reducing the problem to smaller versions of itself Has one or more base cases (which can be solved without recursion) Implemented using recursive methods

Tracing a Recursive Method


Recursive method:
Has unlimited copies of itself (in theory) Every recursive call has its own:
Code Set of parameters Set of local variables

Tracing a Recursive Method


After completing a recursive call:
Control goes back to the calling environment Recursive call must execute completely before control goes back to previous call Execution in previous call begins from point immediately following recursive call

Designing Recursive Methods


Understand problem requirements Determine limiting conditions Identify base cases

Designing Recursive Methods


Provide direct solution to each base case Identify general cases Provide solutions to general cases in terms of smaller versions of general cases

Examples

Factorial (n) - iterative


Factorial (n) = n * (n-1) * (n-2) * ... * 1 for n > 0 Factorial (0) = 1 int IterFact (int n) { int fact =1; for (int i = 1; i <= n; i++) fact = fact * i; return fact; }

Recursive Factorial Method


public static int fact(int num) { if (num = = 0) return 1; else return num * fact(num 1); }

Another Recursive Definition


Fibonacci sequence: 1, 1, 2, 3, 5, 8, 13, 21, . 1 for n == 1 fib(n) = 1 for n == 2 fib(n-2) + fib(n-1) for n>2

GCD design
a if b ! 0 gcd(a, b) ! b if a ! 0 gcd(b, a mod b) otherwise Greatest Common Divisor Recursive Definition

gcd(10, 25) gcd(25, 10) gcd(10, 5) gcd(5, 0)

Towers of Hanoi: Three Disk Problem

Move two disks from source to auxiliary needle.

Move two disks from auxiliary to destination needle.

Towers of Hanoi: Recursive Algorithm


public static void moveDisks(int count, int needle1, int needle3, int needle2) { if (count > 0) { moveDisks(count-1, needle1, needle2, needle3); System.out.println("Move disk +

"

+ count

"

from needle

"

+ needle1 +

+ needle3 + moveDisks(count-1, needle2, needle3, needle1); } }

" to needle " ". ");

Implementations of Recursions
Thee are several implementations of recursions such as Tail recursion NonTail Recursion Indirect recursion Nested Recursion Excessive recursion

Tail Recursion
Tail-recursive functions are functions in which all recursive calls are tail calls and hence do not build up any deferred operations. For example, the gcd function can be considered as a tail-recursive.

Tail recursion:

//INPUT: Integers x, y such that x >= y and y > 0

int gcd(int x, int y) { if (y == 0) return x; else return gcd(y, x % y); }

In contrast, the factorial function is not tailrecursive; because its recursive call is not in tail position, it builds up deferred multiplication operations that must be performed after the final recursive call completes.
//INPUT: n is an Integer such that n >= 1

int fact(int n) { if (n == 1) return 1; else return n * fact(n - 1); }

The significance of tail recursion is that when making a tail-recursive call, the caller's return position need not be saved on the call stack; when the recursive call returns, it will branch directly on the previously saved return position. Therefore, on compilers that support tailrecursion optimization, tail recursion saves both space and time.

void non prog(int i) { if (i>0) { prog(i-1); System.out.print(i+""); prog(i-1); }} This is not a tail recursion since there is an earlier recursive call, other than the last one. In tail recursion, the recursive call should be the last statement, and there should be no earlier recursive calls whether direct or indirect.

Advantage of Tail Recursive Method


Tail Recursive methods are easy to convert to iterative.
void tail(int i) {if (i>0) { system.out.println(i+""); tail(i-1); } }

void iterative(int i) { for (;i>0;i--) System.out.println(i+""); }

Smart compilers can detect tail recursion and convert it to iterative to optimize code Used to implement loops in languages that do not support loop structures explicitly. (e.g. prolog)

Non Tail Recursion


Recursive methods that are not tail recursive are called non-tail recursive.

Is the factorial method a tail recursive method?


int fact(int x) { if (x==0) return 1; else return x*fact(x-1); }

When returning back from a recursive call, there is still one pending operation, multiplication. Therefore, factorial is a non-tail recursive method.

Indirect Recursion
If X makes a recursive call to X itself, it is called direct recursion. Indirect recursive methods call themselves indirectly through calling other methods. In general, indirect recursion is a circular sequence of two or more recursive calls: X1 --> X2 --> ... --> X1.

Indirect Recursion Example


Three method for decoding information are: receive: stores information in buffer and calls decode. decode: converts information to new form and calls store store : stored information in a file, call receive. We have a chain of calls: recieve() -> decode() -> store() ->recieve()-> decode()....

receive (buffer) while buffer is not filled up if information is still incoming


get a character and store it in buffer;

else exit( ); decode (buffer);

decode (buffer) decode information in buffer; store (buffer); store (buffer) transfer information from buffer to file; receive (buffer);

Nested Recursion
When a recursive method has a parameter defined in terms of itself, it is said to be nested recursive.

Another good example is a very important function originally suggested by Wilhelm ckermann in 1928 and later modified by Rozsa Peter:
Ackerman formula

To see how the Ackermann function grows so quickly, it helps to expand out some simple expressions using the rules in the original definition. For example, we can fully evaluate A(1,2) in the following way:

Excessive Recursion
Some recursive methods repeats the computations for some parameters, which results in long computation time even for simple cases. This can be implemented in Java as follows:
int fib(int n)

{ if (n<2) return n; else return fib(n-2)+fib(n-1); }

Consider Fibonacci numbers. A sequence of Fibonacci numbers is defined as follows:

The definition states that if the first two numbers are 0 and 1, then any number in the sequence is the sum of its two predecessors. But these predecessors are in turn sums of their predecessors, and so on

To show how much this formula is inefficient, let us try to see how Fib(6) is evaluated.
int fib(int n) { if (n<2) return n; else return fib(n-2)+Fib(n-1); }
Fib(6) Fib(5) Fib(4) Fib(4) Fib(2) Fib(0) Fib(1) Fib(1) Fib(3) Fib(2) Fib(0) Fib(1) Fib(1) Fib(3) Fib(2) Fib(0) Fib(1) Fib(0) Fib(2) Fib(1) Fib(1) Fib(3) Fib(2) Fib(0) Fib(1)

For caculating fib(6), the method is called 25 times. The same calculation are repeated again and again because the system forgets what have been already calculated. The method is called 2*fib(n+1)-1 times to compute fib(n). 3,000,000 calls are needed to caculate the 31st element. The method is simple and easy to understand but extremely inefficient fibonacci heap.

Disadvantages of Recursion
Recursive functions are generally slower than nonrecursive functions. Excessive recursion may overflow the run-time stack. One must be very careful when writing recursive functions; they can be tricky.

Das könnte Ihnen auch gefallen