For example, the following is a recursive function:
void foo(int x) { ... foo(37); ... }As an example, we could use a recursive function to obtain and validate user input:
#include <cstdio> int GetPositiveNumber(); // repeatedly prompt a user and read responses until a positive // integer is obtained, then return the integer int main() { int x; x = GetPositiveNumber(); printf( "Obtained value %d\n", x); } int GetPositiveNumber() // repeatedly prompt a user and read responses until a positive // integer is obtained, then return the integer { // prompt user and read response printf( "Please enter a positive integer\n"); numRead = scanf("%d", &data); // if nothing was read, the user entered non-integer data, // read and diiscard it then call GetPositiveNumber // again to obtain valid input if (numRead < 1) { scanf("%*s"); printf("ERROR: that was not an integer\n"); data = GetPositiveNumber(); } // if response is invalid, then call the GetPositiveNumber // function again to obtain valid input else if (data < 1) { printf( "ERROR: %d is not a positive integer\n", word); data = GetPositiveNumber(); } return data; }Note on how results are computed:
A typical structure for a recursive function is as follows:
return_type function_name(parameter list) { if (completion condition) { computation to get the answer directly } else { computation plus recursive call } return value; }If the function has no "completion condition" then essentially it will be stuck in an infinite sequence of recursive calls: sooner or later you must compute an answer without needing to make yet another function call.
Generally speaking, the recursive call is made on a smaller, or simpler version of the problem.
For example, suppose we want to calculate factorials:
N! = 1*2*3*...*N
N
is 1 or 2,
N!
equals N
N
is greater than 2,
we know that N!
= (1*2*...*(N-1))*N,
i.e. N! = (N-1)! * N
(N-1)!
we could use
it to calculate the value of N!
int factorial(int N) { int result; if (N <= 2) { result = N; } else { result = factorial(N-1) * N; } return result; }Note that we have a quitting condition - for the cases where it is simple to calculate the result without making a recursive call - and a recursive call (plus a little extra computation) to calculate the more "difficult" cases.
When we make a call like x = factorial(5);
what sequence of calls occurs?
factorial(5) factorial(4) factorial(3) factorial(2) at this point the values are passed "back up the line" - i.e. factorial(2) returns 2 then factorial(3) returns 6 then factorial(4) returns 24 then factorial(5) returns 120
Although the source code may be shorter, when it runs it may involve a great many recursive calls
Function calls themselves tend to be slow: a typical function call may take ten times as long to execute as an integer addition statement
Function calls also take up memory - each time you call a function it sets aside space for local variables and a small block of other information
Thus iterative functions are often more efficient in running time and use of memory, but are sometimes more difficult to code correctly
Fibonacci(3) = Fibonacci(1) + Fibonacci(2) = 1 + 1 = 2 Fibonacci(4) = Fibonacci(2) + Fibonacci(3) = 1 + 2 = 3 Fibonacci(5) = Fibonacci(3) + Fibonacci(4) = 2 + 3 = 5 Fibonacci(6) = Fibonacci(4) + Fibonacci(5) = 3 + 5 = 8 Fibonacci(7) = Fibonacci(5) + Fibonacci(6) = 5 + 8 = 13 etc.Recursive function to calculate Fibonacci numbers:
int fibonacci(int N) { int x, y; if (N < 3) { // simple completion case return 1; } else { // recursive case x = fibonacci(N-1); y = fibonacci(N-2); return x + y; } }Suppose in
main
we make the function call
x = fibonacci(4);
in the call to fibonacci(4) 4 is not < 3, so we perform the recursive calls: x = fibonacci(3) in the call to fibonacci(3) 3 is not < 3, so we perform the recursive calls: x = fibonacci(2) in the call to fibonacci(2) 2 < 3, so we return 1 i.e. x = 1 y = fibonacci(1) in the call to fibonacci(1) 1 < 3, so we return 1 i.e. y = 1 return 1 + 1 i.e. x = 2 y = fibonacci(2) in the call to fibonacci(2) 2 < 3, so we return 1 i.e. y = 1 return 2 + 1 i.e. fibonacci(4) returns 3
Boolean palindromecheck(string str, int first, int last) { // check if you're down to 0 or 1 characters if (last <=first) { return(true); } // check if first char matches last char else if (str[first] != str[last]) { return(false); } // ok so far, check the string in the middle else { return(palindromecheck(str, first+1, last-1)); } }
result = palindromecheck(mystring, 0, size-1);
on the first call to palindromecheck, first = 0, last = 4 last > first, so we don't return true mystring[0] is 'a', and mystring[4] is 'a', so we don't return false make recursive call to palindromecheck with first = 1, last = 3 last > first, so we don't return true mystring[1] is 'r', and mystring[3] is 'r', so we don't return false make recursive call to palindromecheck with first = 2, last = 2 last == first, so return true return result of recursive call, i.e. return true return result of recursive call, i.e. return true
Now suppose we are given another number, N, and asked to determine if N is in the array, and if so where?
Binary search proceeds as follows:
int binarysearch(float arr[], float key, int low, int high) // low and high indicate the boundaries of the portion // of the array we still need to search // // binarysearch returns -1 if the key is not found in arr[], // otherwise it returns the array index at which the key was found { int middle; // used for computing the midpoint of the // section we still need to search if (high < low) { return(-1); // key not found, no space left to search } // find middle of array and check for key middle = (high + low) / 2; if (key == arr[middle]) { return(middle); // got lucky and found the key } // if key not found, make recursive call to search // upper half or lower half, ass appropriate else if (key < arr[middle]) { // key is less than middle element, so // search the lower half of the current section return(bsearch(arr, key, low, middle-1); } else { // key is greater than middle element, so // search the upper half of the current section return(bsearch(arr, key, middle+1, high); } }
int keypos; float key; float myarray[size]; // do something to initialize myarray and key values keypos = binarysearch(myarray, mykey, 0, size-1);
The disks sit on the pegs (the pegs go through the holes) but you are never allowed to put a smaller disk on top of a larger one.
#include <cstdio> void hanoi(int n, char source, char goal, char spare); int main() { int disks; printf( "We have 3 pegs, called A, B, and C\n"); printf( "In the beginning all the disks will be on peg A\n"); printf( "The task is to legally get them all moved to peg B\n"); printf( "How many disks do you want to move?\n"); scanf("%d", &disks); printf( "The correct sequence of moves is as follows:\n"); hanoi(disks, 'A', 'B', 'C'); } void hanoi(int n, char source, char goal, char spare) { if (n == 1) { printf( "Move disk from %c", source); printf( " to %c\n", goal); } else { hanoi(n-1, source, spare, goal); printf( "Move top disk from peg %c", source); printf( " to peg %c\n", goal); hanoi(n-1, spare, goal, source); } }