Detailed analysis of recursive algorithms

Source: Internet
Author: User

C supports the implementation of recursive functions through the run-time stack. A recursive function is a function that calls itself directly or indirectly.
Many textbooks use computer factorial and Fibonacci to illustrate recursion, and unfortunately our lovely famous old Tam teacher's "C programming" is a recursive function that begins with the calculation of factorial. The students who read this book, see the first idea of factorial calculation is recursion. But in the calculation of factorial, recursion does not provide any superiority. In the Fibonacci series, it is more inefficient and very frightening.

Here is a simple program that can be used to illustrate recursion. The purpose of the program is to convert an integer from a binary form into a printable character form. For example: Given a value of 4267, we need to sequentially produce the characters ' 4 ', ' 2 ', ' 6 ', and ' 7 '. As with the%d format code used in the printf function, it performs similar processing.

Our strategy is to divide this value by 10 and print the remainder. For example, the remainder of 4267 except 10 is 7, but we cannot print the remainder directly. What we need to print is a value representing the number ' 7 ' in the machine character set. In ASCII, the value of the character ' 7 ' is 55, so we need to add 48来 to the remainder to get the correct character, but using character constants instead of integral constants can improve the portability of the program. The ASCII code of ' 0 ' is 48, so we use the remainder plus ' 0 ', so there is the following relationship:

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

From these relationships, it is easy to see the code that adds ' 0 ' to the remainder to produce the corresponding character. The remainder is then printed. The next step is to fetch the value of the quotient, 4267/10 equals 426. Then repeat the above steps with this value.

The only problem with this approach is that it produces the opposite number order, which is reversed. So we use recursion to fix this problem in our program.

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

The recursive implementation of this program implements some kind of spiral while loop. While loops must make some progress in each execution of the loop body, and the loop termination condition is gradually approaching. The same is true of recursive functions, which must become more and more close to certain constraints after each recursive invocation. when a recursive function conforms to this constraint, it does not call itself .

In the program, the restriction of the recursive function is that the variable quotient is zero. Before each recursive call, we divided the quotient by 10, so every recursive call, its value is getting closer to 0. When it finally becomes zero, recursion terminates.

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

#include <iostream>using namespace std;void binary_to_ascii (unsigned int value) {    //unsigned int quotient;    QUOTIENT=VALUE/10;    if (value%10!=0)        binary_to_ascii (VALUE/10);    cout<<value%10+ ' 0 ';} int main () {    binary_to_ascii (3);    cout<<endl;    Binary_to_ascii (3747);}


How does recursion help us print these characters in the correct order? Here is the workflow for this function.
1. Divide the parameter value by 10
2. If the value of quotient is nonzero, call Binary-to-ascii to print the number of quotient current value

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

Note in the 2nd step, we need to print the numbers for the current value of quotient. The problem we face is exactly the same as the original question, except that the value of the variable quotient is smaller. We solved this problem by using the function we just wrote (converting integers to individual numeric characters and printing them). Because the value of the quotient is getting smaller, recursion eventually terminates.

Once you understand recursion, the easiest way to read a recursive function is not to dwell on its execution, but to believe that the recursive function will accomplish its task successfully. If each of your steps is correct, your constraints are set correctly, and you are closer to the limit after each call, the recursive function always completes the task correctly.

However, to understand how recursion works, you need to track the execution of recursive calls, so let's do the work. The key to tracking the execution of a recursive function is to understand how the variables declared in the function are stored. When a function is called, the space of its variables is created on the runtime stack. Variables of previously called functions are thrown on the stack, but they are obscured by the variables of the new function and therefore cannot be accessed.

This is the case when the recursive function calls itself. Each time a new call is made, a batch of variables is created that will obscure the variable that was created by the previous invocation of the recursive function. When I follow the execution of a recursive function, it is necessary to separate the variables that are called by the scores differently to avoid confusion.

The function in the program has two variables: parameter value and local variable quotient. Some of the graphs below show the status of the stack, which is currently accessible at the top of the stack. All other called variables are shaded in shades of gray, indicating that they cannot be accessed by the currently executing function.

Suppose we call a recursive function with a value of 4267. When the function is just beginning to execute, the contents of the stack are as follows:


After the division is performed, the contents of the stack are as follows:



Next, the If statement determines that the value of quotient is nonzero, so a recursive call is performed on the function. When the function is called the second time, the contents of the stack are as follows:


A bunch of new variables are created on the stack, hiding the previous batch of variables, unless the current recursive call returns, otherwise they cannot be accessed. After the division operation is performed again, the contents of the stack are as follows:


The value of quotient is now 42 and is still nonzero, so you need to continue with recursive calls and create a batch of variables. After performing the start operation of this call, the contents of the stack are as follows:


At this point, the value of quotient is nonzero, and recursive calls still need to be performed. After performing the division operation, the contents of the stack are as follows:

The statements executed so far are only division operations and test the value of quotient, not the recursive call statement itself. Because recursive invocation of these statements is repeated, it works like a loop: when the value of quotient is nonzero, it restarts the loop with its value as the initial value. However, recursive calls will hold some information (which is different from the loop), and it is good to keep the values of variables stored on the stack. This information will soon become very important.

Now that the value of quotient becomes 0, the recursive function no longer calls itself, but instead begins printing the output. The function then returns and begins destroying the value of the variable on the stack.

Each call to Putchar gets the last number of the variable value, which is a modulo 10 take-out operation of 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 that corresponds to the number, and then print out the character.

Output 4:


The function then returns, and its variables are destroyed from the stack. Then, the previous invocation of the recursive function resumes execution, and she uses her own variables, which are now on top of the stack. Because its value is 42, the number printed after calling Putchar is 2.

Output 42:


The call to the recursive function is also returned, and its variables are destroyed, at the top of the stack is the variable that the recursive function was called before. The recursive call proceeds from this position, and the number printed this time is 6. Before this call returns, the contents of the stack are as follows:

Output 426:


Now we have expanded the entire recursive process and returned to the original invocation of the function. This call prints out the number 7, which is the remainder of its value parameter except 10.

Output 4267:


The recursive function then returns to the location where other functions call it.
If you line up the printed characters one by one and appear on the printer or screen, you will see the correct values: 4267

Recursive algorithm analysis of Hanoi tower problem:

There are three pillars in a temple, and the first one has 64 plates, and the plates are getting bigger and larger from the top down. Ask the old monk in the temple to move all 64 plates to the third pillar. When moving, there is always a small plate pressing on a large plate. And you can only move one at a time.

1, at this time the old monk (later we call him the first monk) find it difficult, so he thought: if there is a person can move the first 63 plates to the second pillar, I will then move the last plate directly to the third pillar, and then let the person to move the first 63 plates from the second column on the third pillar, My task is complete, simple. So he looked for a younger monk than him (we called him a second monk later) and ordered:

①, you move the first 63 plates to the second pillar.

② and then I moved the 64th plate to the third pillar myself.

③, you move the first 63 plates to the third pillar.

2, the second monk took the task, also found it difficult, so he also and the first monk like: if there is a person can move the first 62 plates to the third pillar, I then the last plate to move directly to the second pillar, and then let the man to the first 62 plates from the third pillar moved to the third pillar, My task is complete, simple. So he also looked for a younger monk than him (we called him the third monk) and ordered:

①, you move the first 62 plates to the third pillar.

② and then I moved the 63rd plate to the second pillar myself.

③, you move the first 62 plates to the second pillar.

3, the third monk took the task, and the task of moving the first 61 plates of gourd words to the ladle to the fourth monk, and so on, until the task handed down to the 64th monk (estimated 64th monk very depressed, no chance also ordered others, because to him here the plate has only one).

4, to the completion of this task, to the completion of their respective duties. Complete the push back:

The 64th monk moves the 1th plate, moves it away, and the 63rd monk moves the 2nd plate he assigns to himself.
The 64th Monk then moved the 1th plate to the 2nd plate. By the completion of the 64th Monk's mission, the 63rd Monk completed the first step of the 62nd Monk's assignment to him.

From the above can be seen, only the 64th Monk's task completed, the 63rd Monk's task can be completed, only 2nd monk----64th Monk's task completed, 1th a monk's task to complete. This is a typical recursive problem. Now we have 3 plates to analyze:

1th Monk Order:

① 2nd Monk You first move the first 2 plates to the second pillar. (with the help of the third pillar)

② 1th Monk I moved the last plate of the first pillar to the third pillar myself.

③ 2nd Monk You move the first 2 plates from the second pillar to the third pillar.

Obviously, the second step is easy to achieve (eh, people are always selfish, the simple left to themselves, difficult to others).

One of the first steps, the 2nd monk he had 2 plates, he ordered:

① 3rd Monk You move the 1th plate of the first pillar to the third pillar. (with the help of the second pillar)

② 2nd Monk I moved the 2nd plate of the first pillar to the second pillar myself.

③ 3rd Monk You move the 1th plate from the third pillar to the second pillar.

Similarly, the second step is easy to achieve, but the 3rd monk he only needs to move 1 plates, so he does not have to send a mission. (Note: This is the condition for stopping recursion, also called the boundary value)

The third step can be broken down into, the 2nd monk still has 2 plates, command:

① 3rd Monk You move the 1th plate on the second pillar to the first pillar.

② the 2nd Monk. I moved the 2nd plate from the second pillar to the third one.

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

The analysis is composed of: 1→3 1→2 3→2 with the third pillar to move to the second pillar |1→3 from the private to their own life | 2→1 2→3 1→3 move to the third pillar with the first pillar | A total of seven steps are required.

If it is 4 plates, then the first Monk's order of the 1th and 3rd steps each have 3 plates, so each need 7 steps, a total of 14 steps, plus the 1th monk 1 steps, so 4 plates in total need to move 7+1+7=15 step, the same, 5 plates need 15+1+15=31 step, 6 plates need 31+1 +31=64 Step ... As a result, it is necessary to move n plates (2 n times)-1 steps.

From the above comprehensive analysis, we know to move n plates from 1 seats (rather the first pillar) to 3 seats (rather the third pillar):

(1) Move the 1-seat (N-1) plate with 3 seats to 2 seats.
(2) Move the nth plate of the 1 seats to 3 seats.
(3) 2 seats (n-1) on the plate with the use of 1 mobile 3 seats.

Use Hanoi (N,A,B,C) below to move the 1-seater n plates to 3 seats with 2 seats.

It is obvious: (1) Step is Hanoi (n-1,1,3,2)
(3) Step is Hanoi (n-1,2,1,3)
In C language, that is:

#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;}

  

Detailed analysis of recursive algorithms

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.