In-depth analysis of Recursive Algorithms in C Language

Source: Internet
Author: User
Tags printable characters

C supports the implementation of recursive functions through the runtime stack. Recursive functions call their own functions directly or indirectly.
Many textbooks use the computer factorial and the Fibonacci series to illustrate recursion. Unfortunately, in the book C Programming by our lovely and famous teacher Lao tan, function recursion begins with the calculation of factorial. The first thought of factorial calculation is recursion. However, recursion does not provide any superiority in factorial calculation. In the Fibonacci series, its efficiency is even lower.

Here is a simple program that can be used to describe recursion. The purpose of a program is to convert an integer from binary to printable characters. For example, if a value of 4267 is given, we need to generate the characters '4', '2', '6', and '7' in sequence '. For example, if the % d format code is used in the printf function, it will execute similar processing.

The strategy we use is to divide this value by 10 repeatedly and print the remainder. For example, if the remainder of 4267 except 10 is 7, we cannot print the remainder directly. We need to print the value of '7' in the machine Character Set. In the ASCII code, the value of '7' is 55, so we need to add 48 to the remainder to get the correct characters. However, you can use character constants instead of Integer constants to increase the portability of programs. The ASCII code of '0' is 48, So we add '0' to the remainder, so there is the following relationship:

'0' + 0 = '0'
'0' + 1 = '1'
'0' + 2 = '2'
...

From these relationships, we can easily see that adding '0' to the remainder produces code with corresponding characters. Then the remainder is printed. The next step is to fetch the quotient value. 4267/10 equals 426. Repeat the preceding steps with this value.

The only problem with this method is that it produces the reverse order of numbers, which are printed in reverse order. So we use recursion in our program to solve this problem.

The function in our program is recursive because it contains a call to itself. At first glance, the function will never end. When a function is called, it will call itself, 2nd calls will also call itself, and so on, it seems to be called forever. This is what we do not understand most when we are new to recursion. However, this does not actually happen.

This program recursively implements some kind of spiral while loop. The while LOOP must make some progress in each execution of the loop body and gradually approach the cycle termination condition. The same is true for recursive functions. After each recursive call, they must get closer to a certain restriction.When a recursive function meets this restriction, it does not call itself..

In a program, the limit of recursive functions is that the quotient variable is zero. Before each recursive call, we divide the quotient by 10. Therefore, the value of each recursive call is getting closer and closer to zero. When it eventually becomes zero, recursion ends.

/* Accept an integer value (unsigned 0, convert it to a character and print it, leading 0 is deleted */

# Include <stdio. h>

Int binary_to_ascii (unsigned int value)
{
Unsigned int quotient;

Quotient = value/10;
If (quotient! = 0)
Binary_to_ascii (quotient );
Putchar (value % 10 + '0 ');
}

How does recursion help us print these characters in the correct order? The following is the workflow of this function.
1. Divide the parameter value by 10
2. If the quotient value is non-zero, call binary-to-ascii to print the numbers of the quotient's current value.

3. Then, print the remainder of the division operation in step 1.

Note that in step 1, we need to print the numbers of the current quotient value. The problem we are facing is exactly the same as the original one, but the value of the variable quotient becomes smaller. We can solve this problem by using the function we just compiled (converting integers into various numeric characters and printing them out. Because the quotient value is getting smaller and smaller, recursion ends.

Once you understand recursion, the easiest way to read a recursive function is not to get stuck in its execution process, but to believe that it will successfully complete its tasks. If each step is correct, Your restrictions are set correctly, and each call is closer to the restrictions, recursive functions can always complete the task correctly.

However, to understand the working principle of recursion, You need to track the execution process of recursive calls, so let's do this. The key to tracking the execution process of a recursive function is to understand how the variables defined in the function are stored. When a function is called, its variable space is created on the runtime stack. Previously called function variables are left on the stack, but they are hidden by the new function variables, so they cannot be accessed.

This is the case when recursive functions call themselves. Each time a new call is made, a batch of variables will be created, and they will mask the variables created in the previous call of recursive functions. When tracking the execution process of a recursive function, you must differentiate the variables called for different scores to avoid confusion.

The function in the program has two variables: parameter value and local variable quotient. The following figures show the stack status. Currently, accessible variables are located at the top of the stack. All other called variables are dimmed, indicating they cannot be accessed by the currently executed function.

Suppose we call the recursive function with the value 4267. The stack content is shown in the following figure when the function is executed:
 


After division is executed, the stack content is as follows:



Then, the if statement determines that the quotient value is non-zero. Therefore, it executes a recursive call to this function. When this function is called for the second time, the stack content is as follows:
 


A batch of new variables are created on the stack to hide the previous batches of variables. They cannot be accessed unless the current recursive call returns. After the division operation is executed again, the stack content is as follows:
 


The quotient value is currently 42 and is still non-zero. Therefore, you need to execute recursive calls and create a number of variables. After the start operation of this call, the stack content is as follows:
 


In this case, the quotient value is still non-zero and recursive call is still required. After the division operation, the stack content is as follows:
 

 

The statement itself is not called recursively. The statements executed so far only perform Division operations and test the quotient value. Because these statements are recursively called for repeated execution, their effects are similar to loops: When the quotient value is not zero, its value is used as the initial value to re-start the loop. However, recursive calls save some information (this is different from the loop), so it is better to save the variable value in the stack. This information will soon become very important.

Now that the quotient value is zero, the recursive function no longer calls itself, but begins to print the output. Then the function returns and destroys the variable values on the stack.

Each time putchar is called to obtain the last number of the variable value, the method is to perform the modulo 10 remainder operation on the value, and the result is an integer between 0 and 9. Add it to the character constant '0', and the result is the ASCII character corresponding to the number, and print it out.

Output 4:

 


Then the function returns, and its variables are destroyed from the stack. Next, the previous call of the recursive function continues execution. She uses her own variables, which are now at the top of the stack. Because its value is 42, the number printed after putchar is called is 2.

Output 42:

 


Then the call of the recursive function is returned, and its variables are also destroyed. At the top of the stack, the variable that the recursive function called again. Recursive call continues from this position. The number printed this time is 6. Before this call is returned, the stack content is as follows:

Output 426:

 


Now we have expanded the entire recursion process and returned to the initial call of the function. This call prints the number 7, that is, the remainder of its value parameter except 10.

Output 4267:

 


Then, this recursive function is completely returned to the location where other functions call it.
If you sort the printed characters one by one and appear on a printer or screen, you will see the correct value: 4267

Recursive Algorithm Analysis for the tower of Hanoi Problem:

There are three pillars in a temple, and the first has 64 dishes, which are getting bigger and bigger from top down. Ask the old monk in the temple to move all the 64 dishes to the third pillar. When moving, you can only press a small plate on a large plate. You can only move one file at a time.

1. At this time, the old monk (we call him the first monk later) felt very difficult, so he thought: if a person could move the first 63 dishes to the second pillar first, I moved the last plate directly to the third pillar, and then the person moved the first 63 plates from the second pillar to the third pillar, my task is complete, simple. So he finds a monk younger than him (we call him the second monk later:

① You have moved the first 63 dishes to the second pillar.

(2) then I moved the 64th plates to the third pillar.

③ You move the first 63 dishes to the third pillar

2. The second Monk took over the task and thought it was difficult, so he thought like the first MONK: if one person could move the first 62 dishes to the Third Pillar first, I moved the last plate directly to the second pillar, and then the person moved the first 62 plates from the third pillar to the third pillar, my task is complete, simple. So he also found a monk younger than him (we call him "third" and "Shang" Later). command:

① You move the first 62 dishes to the third pillar

(2) Then I move the first plate to the second pillar.

③ You move the first 62 dishes to the second pillar

3. The third Monk took over the task and handed over the task of moving the first 61 dishes to the fourth monk according to the words of the gourd, until the task has been handed over to 64th monks (it is estimated that 64th monks are very depressed and have no chance to give orders to others, because there is only one plate here ).

4. Submit the task to complete the assignment. Push back:

The 64th monks moved 1st dishes and removed them. Then the 63rd monks moved the 2nd dishes They allocated to themselves.
The third monk moved 64th more dishes to the third. Here, the task of the 64th monks is completed, and the 63rd monks have completed the first step of the task assigned to them by the 62nd monks.

It can be seen from the above that only 64th monks have completed their tasks and 63rd monks have completed their tasks. Only after the tasks of 2nd monks-64th monks have been completed, the task of 1st monks can be completed. This is a typical recursive problem. Now we have three plates for analysis:

1st monk commands:

① You shall first move the first two plates of the first pillar to the second pillar. (Using the third pillar)

② I moved the last plate of the first pillar to the third pillar.

③ You move the first two plates from the second pillar to the third pillar.

Obviously, the second step is very easy to implement (ah, people are always selfish, leaving simplicity to themselves and giving difficulties to others ).

In the first step, the first monk had two plates and he ordered:

① 3rd monks you move the first pillar of 1st plates to the third pillar. (Using the second pillar)

② I moved 2nd dishes on the first pillar to the second pillar by myself.

③ 3rd monks you move 1st dishes from the third pillar to the second pillar.

Similarly, the second step is easy to implement, but the first monk only needs to move one plate, so he does not have to dispatch the task. (Note: This is the condition for stopping recursion, also called the boundary value)

The third step can be divided into two dishes for the 2nd monks. The command is as follows:

① 3rd monks you move the 1st plates on the second pillar to the first pillar.

② 2nd monks I moved 2nd dishes from the second pillar to the third pillar.

③ 3rd monks move the plate on the first pillar to the third pillar.

The combination of analysis is: 1 → 3 1 → 2 3 → 2 move to the second pillar with the help of the third pillar | 1 → 3 the activity left for the selfish person | 2 → 1 2 → 3 1 → 3 use the first pillar move the column to the third column | seven steps are required.

If there are four plates, the first monk's command contains three plates in step 1 and step 2, so each of them requires 7 steps and 14 steps in total, add one step of 1st monks, so four plates need to move 7 + 1 + 7 = 15 steps in total. Similarly, five plates need 15 + 1 + 15 = 31 steps, 31 + 1 + 31 = 64 steps for 6 dishes ...... From this we can know that moving n plates requires (n times of 2)-1 step.

From the overall analysis above, we can see that the n plates are moved from one (equivalent to the first pillar) to three (equivalent to the third pillar ):

(1) move one N-1) plate to two with three.
(2) Move the n plates on the first seat to the third seat.
(3) Move two (n-1) dishes on one seat to three.

The following uses hanoi (n, a, B, c) to move one n plates to three with two.

Obviously: (1) the step is hanoi (n-1, 1, 3, 2)
(3) The step is hanoi (n-1, 3)
It is shown in C language:
# Include <stdio. h>
Int method (int n, char a, char B)
{
Printf ("number... % d... form... % c .. to... % c .." n ", n, a, B );
Return 0;
}
Int hanoi (int n, char a, char B, char c)
{
If (n = 1) move (1, a, c );
Else
{
Hanoi (n-1, a, c, B );
Move (n, a, c );
Hanoi (n-1, B, a, c );
};
Return 0;
}
Int main ()
{
Int num;
Scanf ("% d", & num );
Hanoi (num, 'A', 'B', 'C ');
Return 0;
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.