You are on page 1of 20

# Recursion

Recursion

At the end of this chapter you will be able to understand the concept of recursion and will learn to implement it in programs.

SCOPE
5.1 Introduction 5.2 Basics of Recursion 5.2.1 Implementation 5.3 Analysis 5.3.1 Examples 5.4 Removal of Recursion 5.5 Tips for Using Recursion

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Chapter 5 155

Recursion

5.1

Introduction

What do you think will be the result, if we execute the following program?
void sum(int a, int b ) { int c; c = a + b; sum(c,a); } void main( ) { int a,b; printf(enter the two values ); scanf(%d,%d,&a,&b); sum(a,b); printf(\ntask completed); }

Will the program compile, execute and give the desired output. As far as compilation is considered, yes the program will compile, as there are no syntax errors. However, if you execute the program, the system will hang. Why does this happen? In our function sum() we have a statement sum(c,a). This statement invokes the sum() function again. The function does not have a way to exit from the program. This process continues until the system runs out of memory. The ability of a function to call itself is known as recursion. This feature is very useful but if not used with proper care can lead to a system crash due to the infinite loop. Recursion as the name suggests is repeating the same process repeatedly. Let us consider a real life example to understand what is recursion. There are five earthen pots kept in a row. There is a river five kilometers away from the place. A person is asked to fill all the earthen pots with river water. The person will use a bicycle to travel from the place to the river. The bicycle can carry a single earthen pot. The process to fill the pots will be as follows. 1) 2) 3) 4) 5) 6) Attach an empty earthen pot to the bicycle. Cycle to the river. Fill the pot. Cycle back to the place. Detach the earthen pot. If all the pots are not filled goto step 1.

The same set of actions is repeated for five times. This problem has a solution that is recursive in nature.

Chapter 5 156

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

Recursion

The second example is from the computer field. We have an integer array of hundred elements. A program is to be written that will take hundred values from the user and store them into the array. The task can be completed as below. 1) Input the first value. 2) Store it in the first location. 3) Input the second value. 4) Store it in the second location. . And so on until the 100 elements are entered and stored. We find that two statements are repeated hundred times. If we were to write a program to solve this problem, we would have used a loop to accomplish the task. All the factors other than the location number remain the same. The code for this will be as follows.
for (i =0; i< 100; i++) { printf(enter the %d value ,i); scanf(%d, &a[i]); }

## The same task can be written as follows.

void user_entry(int i) { if(i<100) { printf(enter the %d value, i); scanf(%d,&a[i]); user_entry(i+1); /*the recursive call */ } }

This program will also enter hundred values from the user and store them. It uses recursive method to solve the problem. The function user_entry () calls itself in the function for this purpose. Why should we use recursive method if the same task can be accomplished through looping? The problem given above was very simple. There are problems that are more complicated and if solved using recursion increase the clarity of programs. We will cover all these points in this chapter. We will use recursion to solve problems in sorting chapter. In this session, we will study recursion, which is one of the methods of programming. You must have already used recursion in the programming languages session. We will revive the concept again. In this session, we will find out how recursion is helpful for programmers. We will also study how to convert recursive functions into iterative one. Recursion helps us to write efficient programs for complicated problems. Initially we will consider small programs that can also be done in non-recursive ways to understand the concept of recursion.

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Chapter 5 157

Recursion

5.2

Basics of Recursion

There are certain problems that can be defined in terms of smaller problems of similar type. Such problems are said to have recursive definition. For example, let us consider the factorial definition.
n! for any non-negative value of n is defined as follows: 1, n! = n*(n-1)!, if n > 0 if n = 0

Here n! is recursively defined in terms of itself. Hence 5! will be calculated as follows. The steps that would occur if we follow the definition will as shown below
5! 4! 3! 2! 1! = = = = = 5 * (5 - 1)! = 5 * 4! 4 * (4 - 1)! = 4 * 3! 3 * (3 - 1)! = 3 * 2! 2 * (2 - 1)! = 2 * 1! 1 * (1 1)! = 1 * 0!

Once we reach the end then the final answer can be found out by passing the answer to the required statement. According to the definition the value of 0! = 1 and hence we can now find out all the values.
1! 2! 3! 4! 5! = = = = = 1 * (1 1)! = 1 * 0! = 1 * 0 = 1 2 * (2 - 1)! = 2 * 1! = 2 * 1 = 2 3 * (3 - 1)! = 3 * 2! = 3 * 2 = 6 4 * (4 - 1)! = 4 * 3! = 4 * 6 = 24 5 * (5 - 1)! = 5 * 4! = 5 * 24 = 120

Another example of recursive definition is the fibonacci series. The fibonacci series is as shown below:
0, 1, 1, 2, 3, 5, 8, 3, 21,

Each element in the series is the sum of the previous two elements.

Chapter 5 158

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

Recursion

The recursive formula for calculating the n th number of the sequence is:
n, fib(n) = fib (n-2) + fib(n-1) if n > 1 if n =0 or n=1

Let us find the value of fib(5). The steps according to the above definition will be as follows:
fib(5) = fib(3) + fib(4) fib(4) = fib(2) + fib(3) fib(3) = fib(1) + fib(2) fib(2) = fib(0) + fib(1)

This will be the last step as according to the definition now we can find out the value of the last step. The final answer will be obtained as follows:
fib(2) = fib(0) + fib(1) = 0 + 1 = 1 fib(3) = fib(1) + fib(2) = 1 + 1 = 2 fib(4) = fib(2) + fib(3) = 1 + 2 = 3 fib(5) = fib(3) + fib(4) = 2 + 3 = 5

The above problems can be defined non-recursively also, but the problem can be clearly understood by recursive method. For example n! can be defined as follows:
1, n! = n*(n-1)*(n-2)*.*1, if n>0 if n=0

The above definition would make a programmer to think for a solution, while the recursive version makes it clear. In the later part of the sessions, we will see the programs for the above problem. The ability of a procedure or function to call itself is known as recursion. This facility is provided by C language. If a programming language does not support recursion then the recursive methods can be implemented using stacks. Recursion is a very powerful programming technique that can be used in place of iteration. It solves a smaller version of the original problem 5.2.1 Implementation A recursive function is a function that involves itself. There are two methods of recursion: Direct recursion: The code for function f() contains a statement that invokes function f() is:

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Chapter 5 159

Recursion

/* The skeleton code for direct recursion, function f() calls itself */
void f () { . . f(); .. }

Whereas in indirect recursion a function f() invokes a function g(), which invokes a function p() and so on until function f() is invoked again. /* The skeleton code for indirect recursion, function f() calls function g(). Function g() inturn calls function p() and p() calls f()again. */
void f() { .. g (..); .. } void g() { .. p (..); .. } void p() { .. f (..); .. }

We had seen an example in the introduction, it did not make any sense as far as logic was concerned. But it showed how the use of recursion without proper exit condition could cause the program to enter an infinite loop. Let us see a piece of code written to find the factorial of a given number.
int { } fact( int n) return(n * fact(n-1));

We have written the code as stated by its definition. Will this code execute properly? No, in fact it will enter an infinite loop. There is no way to come out of the function. In every call to fact() there is a recursive call made to fact(). So we conclude that there should be a condition on which the program comes out of recursion. There is a method to check the validity of a recursive function. This method helps us to find out whether a given problem can be solved using recursion. The method has two cases, which help in determining a valid recursive function.

Chapter 5 160

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

Recursion

The two cases are: 1) The Base case: Is there a non-recursive way out of the procedure or function. 2) The Smaller-Caller case: Does each recursive call to the procedure or function involve a smaller case of the original problem leading inescapably to the base case. Let us apply the above test to the factorial problem, according to the definition we find that: 1) The Base case: The definition says if n=0 then factorial is 1 and then it comes out of the recursion and n cannot be negative. 2) The Smaller-Call case: The next call to factorial will be n-1, hence it will surely lead to the base case of n=0. We find that both the cases are satisfied, hence we can write a recursive function for factorial as follows:
int fact( int n) { if (n < = 0)

/* base case condition checked and recursive exit from the function */

non-

return (1); else return(n * fact(n-1)); /* smaller case condition is satisfied by the recursive call with the parameter n-1, so the base condition will be reached. */ } void main() { int m; printf(enter the value of the number to find the factorial.); scanf(%d,&m); printf(the factorial is %d,fact(m)); }

In the above function, we find that the function fact returns an integer value. So when the base case is reached then it returns 1 and there are no further calls made to fact(). If the base case is not reached then a recursive call is made to fact() with n1 as the parameter. Let us see how recursion works internally. When a subprogram is invoked, it needs space to keep its formal parameters, local variables and the return address. These values are stored on a stack. The values on the top of the stack belong to the latest invoked sub program. Each invocation for a sub program or function needs a workspace. This

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Chapter 5 161

Recursion

workspace is called an activation record. All the values are stored in this activation record. It is stored on top of the stack. This stack is called as the run time stack. When a subprogram completes its execution its activation record is popped from the stack and the program control is transferred to the next line from where the call was made. In recursion, the program invokes itself. The number of activation records created of the function for a particular instance is known as the depth of recursion. Let us see the stack for factorial call fact(3). The contents of the stack are formal parameter, local parameter and the return address. We do not have any local variable and the return address will be the point where a function transfers control of the program after it finishes its execution. We will show only the formal parameters on the stack. The arrows will show the flow of the program. The first activation record is created for the main program and the value of m is stored as 3. This is shown in fig 5.1(a). The first call to fact() is made from the main() program and it stores the value of the formal parameter. This forms the second activation record. The stack looks like as shown in the fig 5.1(b). The call made is fact(3).
First call to fact n=3 Main program m=3 Main program n=3

fact(3)

Fig. 5.1

(a)

## Fig. 5.1 (b)

The next two recursive calls are made similarly and can be represented as follows. Now the stack looks as shown in the fig. 5.1 (d).
3 rd call to fact n=1 2 nd call to fact n=2 First call to fact n=3 Main program n=3 Fig. 5.1(d) fact(1)

2 nd call to fact n=2 First call to fact n=3 Main program n=3 Fig, 5.1 (c)

fact(2)

Finally, the last call is made as fact(0). According to our base condition, when n=0 then return 1. The return value 1 is transferred to the next activation record on the stack.

Chapter 5 162

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

Recursion

return(1)

## 4 th call to fact n =0 3 rd call to fact n=1

fact(0)

2 nd call to fact n=2 First call to fact n=3 Main program n=3 Fig. 5.1 (e)

The topmost activation record is removed from the task and the control is given to the previous activation record along with the return value. This is shown in the fig 5.1 (e) and 5.1 (f).
3 rd call to fact n=1 2 nd call to fact n=2 First call to fact n=3 Main program n=3 Fig. 5.1 (f)

return (1 * 1) = 1

This process continues until the final value is found. This value is passed to the main function that will print it. Finally, all the activation records will be removed from the stack.
2 nd call to fact n=2

return (2 * 1) = 2

First call to fact n=3 Main program n=3 Fig. 5.1 (g)

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Chapter 5 163

Recursion

return (2 * 3) = 6

First call to fact n=3 Main program n=3 Fig. 5.1 (h)

Until now we have seen mathematical problems and solved them. Let us consider some problem close to data structures. Like finding an element from an array. Recursion may not be a suitable solution for this problem due to the memory it requires, but it will show us how recursion can be used. The problem is defined as follows find an element X from an array A with N elements. The first step is to find out whether this problem has a valid recursive solution. We can do this by finding out the two cases. 1) The Base case: If the value of A[j] is equal to X then the element is found and if j<0 then the element is not present, the program will terminate for both the cases 2) The Smaller Call case: Every time a recursive call is made one location will be searched, and we will search all the locations until j is not equal to zero.
int find_element ( int j) { if (A[j] = = X) . return(1); else if (j = = 0) return (0); else find_element(j-1); }

The first call will be made as found = find_element (N-1); where found is an integer. If found is 1 then the required element is present else if it is 0 then the element is not present. Let us take an example and see how the function works. Array A has 5 elements. The array looks as shown below. 0 1 2 3 4 A: 20 10 2 5 7 We have to find whether 2 is present in the array. So the value of X is 2. The function will be executed as follows: First call will be find_element(4). This will invoke the function find_element(3). The fourth position in the array doesnt have the value 2 and there are more elements to be examined, the next call will be find_element(2) from the find_element(3) function. Here A is equal to 2, hence the function returns 1. This value is assigned to found.

Chapter 5 164

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

Recursion

Let us take another problem where the value doesnt exists in the array. The value of X is 15. The calls will be as follows:
find_element(4) find_element(3) find_element(2) find_element(1) find_element(0)

Here the statement if j == 0 is true and hence the program returns zero. This value is assigned to found. The programs where the recursive call is the last statement executed are said to have tail recursion. It is not necessary that the last statement in the function is a recursive call, it is the last executed statement of the function. For example, the code given below is also having tail recursion.
int find_element(int j) { if (A[j] = = X ) find_element = 1; else if ( j ! = 0 ) find_element = find_elemnt(j-1); else find_element = 0; }

Here if there is a recursive call to the find_element function then it will be the last line to be executed though it is not the last line of the program code. /* Iterative version of find_element*/
int find_element(int j) { int i, flag = 0; for(i =0;i<j;i++) { if (A[I] = = X) { flag = 1; break; } } return(flag);

Hence, we conclude that a recursive problem has a group of steps, which are carried out repeatedly. We find that the recursive version is more readable and elegant than the iterative version of search method. If a problem has a condition, which allows it to come out of the repetitive action then it is possible to use recursion. By now it must be clear how to find out whether recursive solution is feasible or not for a given problem statement. We will study a few more examples on recursion in the following sections.
Chapter 5 165

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Recursion

5.3

Analysis

Till now we have seen how to implement recursion. Now we will explore why recursion is essential, how efficient it is and how can we convert recursive programs into nonrecursive ones. Before that, we will study a few more examples, which will help us to understand and analyze recursion properly. 5.3.1 Examples 1) Binary search: This search technique requires the list of elements to be in ascending order. In this method, we are suppose to find the mid of the given array, if the mid value equals to the value we wish to find then the search terminates, else if the mid value is greater than the required value then it means that the element lies somewhere in the first half of the array and if the mid value is smaller, then the element lies in the second half of the array. The diagram below will make it clear.

## second half of the array (5 to 8)

Fig 5.2 Array of 9 elements

Now let us find out the conditions required for a valid recursive function. 1) The Base case: If mid value is equal to the element then we have found the required value and if start > end then all the possible locations are searched. On both the conditions, the program exits. 2) The Smaller Call case: if mid value is greater than the required value then binary search the first half of the array and if the mid value is less then binary search the second half of the array. So we find that the array size will go on decreasing until the condition start > end is met or the element is found. We will write the code for binary search. The various assumptions are, A[0,n] is the sorted array, x is the element to be found in the array, start is the start index , and end is the end index. They are the formal parameters of the function.

Chapter 5 166

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

Recursion

## The function will be as follows:

int { binsearch( int start, int end)

int mid; if( start > end) return(0); else { mid = (start + mid ) / 2; if A[mid] = x return (1); else if A[mid] > value binsearch(start, mid 1); else binsearch(mid+1, end); } }

This was about binary search method. 2) Reverse Printing of Singly Linked List: Can you print a singly linked list in reverse order i.e. from the last node to the first node? As there is no link from a node to its previous node, it seems to be impossible to do so. But this is possible using recursion. How? We will see in this in the second example. We will assume certain things about linked list before proceeding to the implementation of this program. We assume that the head pointer of the list is declared as follows.
node * head;

## The structure of each node is as follows:

typedef struct node { int no; node * next; };

The evaluation of the base and smaller call cases will be as follows: 1) The Base case: List is empty, then exit the function. This means the function will end when all the nodes are visited. 2) The Smaller Call case: In each recursive call the node pointed to by the present node is passed as a parameter. Hence there will be a node whose next pointer will be null and it will be the end of the linked list.

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Chapter 5 167

Recursion

## void reverse_print( node * loc) { if (loc != NULL) { reverse_print(loc->next); print(loc->no); } }

The first call to this function will be reverse_print(head). In this function, the recursive call is not the last line of execution it is not a case of tail recursion. Each time a call is invoked for reverse_print(), a new activation record is stacked. As we know the activation record will have the formal parameter (loc) and the return address stored in it. Once all the nodes are visited then the printing process starts, as the activation record stores the values of loc, records are printed in the reverse order. This is possible because the print statement is after the recursive call and it is executed after all the nodes are visited. As the records are stored in a stack, the reverse printing is possible.

5.4

Removal of Recursion

Recursion may not be desirable due to some conditions like the language does not support recursion or if the recursive version is not feasible due to time and space constraints. At such times, it is essential to substitute recursion in the program. There are two ways to transform a recursive program to a non-recursive one viz. 1) Iteration 2) Stacking We will study these methods with examples in the following section. 1) Iteration We have seen a particular type of recursion known as tail recursion in the previous sessions. If the recursive call is the last executable line of the program then it is said to have tail recursion. Let us explore how this type of recursion functions. We know each call to the function saves the parameters, local variables and return address on the stack as an activation record. These values are stored, so that they can be used when the control returns to that particular function. As we know that in tail recursion the recursive call is the last statement to be executed, hence when the control is returned to the function the next step is to exit from the function. In this case, the parameters and the variables are not used at all. Only the return address is used to transfer the control to the previous function. From the above discussion we conclude that there is no need to remember the values of the local and the formal parameters, we should know where the control should be transferred after each execution and the smaller call case should be followed. These things can be done using an iterative loop. The control is transferred at the beginning of the loop every time it comes to the end of the loop, the base condition becomes the conditional statement for the loop and the loop variable can be changed according to the smaller call case.

Chapter 5 168

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

Recursion

Let us consider the binary search method as an example. Binary search method has tail recursion present in it. Every recursive call stores the values of start, end, x and mid values on the stack, but these values are not used later. The code for non-recursive binary function is given below
int binsearch ( int start, int end, int x ) { int mid;

the base case used as the conditional while (start <= end ) statement { mid = (start + end) / 2; if A[mid] = x; return(1); else if A[mid] > x smaller call case end = mid 1; else start = mid + 1; } if (start > end) return(0); }

We find that the base case (start > end) is used as the conditional statement for the loop. If the element is found then there is a return statement used to come out of the function. The smaller call case is taken care of by changing the values of start and end as per the rules of the binary search method. If the mid value is smaller than the required element then the value of start is changed and if it is greater then the end value is changed. Tail recursion is usually replaced by iterative methods. It is the easiest way to make a non-recursive program. 2) Stacking Now consider the problem of reverse printing of singly linked list. The recursive call is not the last line of execution. It is not having tail recursion. The next statement uses the parameter value to print the record. This value is obtained from the activation record stored on the stack. Hence, it is necessary to store the value of parameters and local variables. These values are to be stored in LIFO manner. Hence, we will use stack to store the values. Then we can simulate the action of recursion for the above program. In the reverse print function, we will have to store a pointer in the stack. There are no local variables. Let us see the algorithm for removal of recursion from the reverse_print() program.

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Chapter 5 169

Recursion

reverse_print()

1) Start. 2) Create an empty stack to store pointers. 3) Start from the first node in the list. 4) Push the value of the pointer on the stack. 5) Go to the next node in the list. 6) If next node is not equal to NULL then go to step 2. 7) Pop the pointer value from the stack. 8) Print the information of the node pointed by the popped pointer. 9) If the stack is not empty then go to step 7. 10) End. On comparing the above algorithm with the function written recursively, we can clearly see that the recursive function is much simpler than the non-recursive function. Recursive programs are more elegant and look as if they are the obvious solution for the problem. A problem, which is very complicated and does seem to have a recursive solution, will lead to a very elegant solution. If such a solution requires a lot of memory and time to execute then we can convert the recursive solution to a non-recursive one using the above methods.

5.5

## Tips for Using Recursion

Let us explore the factors on which we can decide whether to use a recursive solution to the given problem. A recursive solution is more costly in terms of time and space but offers elegant and clear programs. A recursive solution has functions that invoke themselves. Every time a new function is invoked an activation record is created and pushed on the stack. When a function completes its execution then its activation record is destroyed and removed from the stack. These tasks, which are to be carried out before and after the execution of a function, require time and the stack requires space. If there are many parameters and variables to be stored on the stack, then it requires a large amount of space. If the depth of recursion is very large then in such a situation the amount of memory required to execute the program is very large as compared to the iterative solution. Depth of recursion is the number of times a function calls itself. In the example discussed above, to find an element from a list, if we have 100 elements in the array then there will be 100 recursive calls made to the function. There will be hundred activation records on the stack, while the iterative version would have required a single activation record. Hence, we find that using recursion is both space and time consuming in this situation. We summarize the use of recursion as follows: 1) If the depth of recursion is not very large and occupies affordable space then recursion can be a better option. For example the binary search, method requires at the maximum O (log 2 n) recursive calls.

Chapter 5 170

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

Recursion

2) If the recursive version does the same amount of work as the non-recursive version, then recursion can be chosen as it gives elegant and clear programs. Again, binary search is a good example. Both the iterative and the recursive versions do almost the same amount of work but recursive program is more readable than the iterative version. 3) If the recursive version is elegant and short as compared to the non-recursive, then it can be used. It will take large amount of space and more time as compared to the nonrecursive version, but at the same time make the code understandable. This was the situation with reverse_print() function used to print the singly link list in reverse manner.

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Chapter 5 171

Recursion

SELF ASSESSMENT
1. Define recursion. What are the two methods of implementing recursion? 2. The two ways to reform a recursive function into a non-recursive one are _______ and ____________. 3. State the differences between the direct recursive function and an indirect one. 4. The workspace is called an _________ record. 5. The number of activation records created of the function for a particular instance is known as _________________. 6. The program where the recursive call is the last statement to be executed is said to have _____________.

Chapter 5 172

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority

Recursion

SUMMARY
The ability of a function to call itself is known as recursion. There are certain problems, which can be defined in terms of smaller versions of it. Such type of problems are said to be have recursive definition In direct recursion the code for function f() contains a statement that involves f(), whereas in indirect recursion function f() invokes a function g(), which invokes a function p() and so on until function f() is invoked again. The method helps us to find out whether a given problem can be solved using recursion. The method has two cases, which help in determining a valid recursive function. The two cases are:

z The Base case: Is there a non-recursive way out of the procedure or function. z The Smaller-Caller case: Does each recursive call to the procedure or function
involve a smaller case of the original problem leading inescapably to the base case Each invocation for a sub program or function needs a workspace. This workspace is called an activation record The number of activation records created of the function for a particular instance is known as the depth of recursion The program where the recursive call is the last statement to be executed is said to have tail recursion. Recursion may not be desirable due to some conditions like the language does not support recursion or if the recursive version is not feasible due to time and space constraints. At such times, it is essential to substitute recursion in the program. There are two ways to transform a recursive program to a non-recursive one viz.

z Iteration z Stacking
Tail recursion is usually replaced by iterative methods. It is the easiest way to make a non-recursive program. A recursive solution is more costly in terms of time and space but offers elegant and clear programs Recursion can be used in the following conditions :

z The depth of recursion is not very large and occupies affordable space. z The recursive version does the same amount of work as the non-recursive version
of the problem. z Recursive version is elegant and short as compared to the non-recursive version.
Chapter 5 173

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority.

Recursion

LAB EXERCISE
1. Write a recursive program to find the minimum and maximum values present in a given array of integers. 2. Write a recursive program to print a string in the reverse order. The string is taken as input from the user. You can use only a single character variable for this program.

Chapter 5 174

Copyright Tata Infotech Ltd. : Copying of this document in part or full is not permitted without express authority