Many textbooks use the computer factorial and Fibonacci sequence to illustrate recursion, unfortunately our lovely famous old Tam teacher's "C language Programming" is a function of the beginning of factorial calculation recursion. The students who have read this scripture see the first idea of factorial calculation as recursion. But in the calculation of factorial, recursion does not provide any superiority. In the Fibonacci series, its efficiency is even lower and very scary.
Here is a simple program that can be used to illustrate recursion. The purpose of the program is to convert an integer from binary form into a printable character form. For example: Given a value of 4267, we need to produce the characters ' 4 ', ' 2 ', ' 6 ', and ' 7 ' in turn. As with%d format codes in the printf function, it performs similar processing.
The strategy we use is to divide this value repeatedly 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 the value in the machine character set that represents the number ' 7 '. 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 the word constants quantity instead of the integer constant can improve the portability of the program. The ASCII code for ' 0 ' is 48, so we use the remainder plus ' 0 ', so we have the following relationship:
' 0 ' + 0 = ' 0 '
' 0 ' + 1 = ' 1 '
' 0 ' + 2 = ' 2 '
...
From these relationships, it's easy to see that adding ' 0 ' to the remainder produces the code for the corresponding character. The remainder is then printed. The next pick up the value of the quotient, 4267/10 is equal to 426. Then repeat the above steps with this value.
The only problem with this approach is that it produces the exact opposite of the order in which the numbers are printed in reverse. So in our program, we use recursion to fix this problem.
The functions in our program are recursive in nature, because it contains a call to itself. At first glance, the function never seems to end. When the function is called, it will call itself, and the 2nd call will also call itself, and so on, it seems to always call down. This is what we most want to understand when we just get in touch with recursion. But this is not actually the case.
This program recursively implements some type of helical while loop. While loops must make some progress each time the loop body executes, it is approaching the cyclic termination condition. The same is true of recursive functions, which have to be closer to some kind of restriction after each recursive invocation. When a recursive function conforms to this constraint, it does not call itself.
In a program, the limiting condition of a recursive function is that the variable quotient is zero. Before each recursive call, we divide the quotient by 10, so each time it is called recursively, its value gets closer to 0. When it finally becomes zero, recursion terminates.
/* Accepts an integer value (unsigned 0, converts it to a character and prints it, leading 0 is deleted * *
Copy Code code as follows:
#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 right order? Here is the workflow for this function.
1. Divide the parameter value by 10
2. If the value of quotient is Non-zero, call Binary-to-ascii print quotient The current value of the numbers
3. Next, print the remainder of the division operation in step 1
Note that in step 2nd, we need to print the numbers for quotient current values. The problem we face is exactly the same as the original problem, except that the value of the variable quotient becomes smaller. We solve this problem by using the function we just wrote (converting integers to individual numeric characters and printing them out). Because the value of the quotient is getting smaller, recursion will eventually terminate.
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 perform its task smoothly. If each of your steps is correct, your restrictions are set correctly, and each call is closer to the limit, and 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 this 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 Run-time stack. The variables of previously called functions are left 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 masks the variables created by the recursive function's previous invocation. When I track the execution of a recursive function, I have to distinguish the variables that are called by the fractions from each other to avoid confusion.
The function in the program has two variables: parameter value and local variable quotient. Some of the following graphs show the state of the stack, and the currently accessible variable is at the top of the stack. All other variables that are called are decorated with shades of gray, indicating that they cannot be accessed by the function currently executing.
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 shown in the following illustration:
After division is performed, the contents of the stack are as follows:
The IF statement then determines that the value of the quotient is Non-zero, so a recursive call is performed on the function. When this function is invoked for the second time, the contents of the stack are as follows:
A batch of new variables is 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, still non-zero, so you need to continue with the recursive call and create a batch of variables. After performing the starting operation of this call, the contents of the stack are as follows:
At this point, the quotient value is still non-zero, and a recursive call is still required. After the division operation is performed, the contents of the stack are as follows:
Not counting the recursive call itself, the statements executed so far are only division operations and the values of quotient are tested. Because these statements are recursively invoked repeatedly, the effect is similar to a loop: when the value of a quotient is not zero, its value is restarted as an initial value. However, the recursive call will save some information (this is different from the loop), and it is the value of the variable stored in the stack. This information will soon become very important.
Now that the value of the quotient is 0, the recursive function does not call itself, but instead begins to print the output. The function then returns and begins destroying the value of the variable on the stack.
Each time you call Putchar, you get the last number of the variable value, which is modulo 10 for value, and the result is an integer between 0 and 9. Add it to the constants quantity ' 0 ', and the result is the ASCII character that corresponds to the number, and then print the character.
Output 4:
Then the function returns, and its variables are destroyed from the stack. Then, the previous invocation of the recursive function resumed, and she was using her own variables, which are now at the top of the stack. Because its value is 42, the number printed after the call to Putchar is 2.
Then this call to the recursive function is returned, and its variables are destroyed, and at the top of the stack is the variable that the recursive function called the previous time. The recursive call continues from this location, and the number printed this time is 6. Before this call returns, the contents of the stack are as follows:
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.
The recursive function is then completely returned to where the other function called it.
If you put the printed characters together one after the other, appear on the printer or screen, you will see the correct value: 4267
Use recursion must have the conditions to jump out:
This is one of the simplest recursion, but it will always execute and can be terminated with CTRL + C.
Copy Code code as follows:
#include <stdio.h>
void prn (int num) {
printf ("%d/n", num);
if (num > 0) PRN (--num);
}
int main (void)
{
PRN (9);
GetChar ();
return 0;
}
Copy Code code as follows:
Instances: Flipping strings
#include <stdio.h>
void revers (char *cs);
int main (void)
{
Revers ("123456789");
GetChar ();
return 0;
}
void revers (char *cs)
{
if (*CS)
{
Revers (cs + 1);
Putchar (*CS);
}
}
Copy Code code as follows:
Instance: factorial
#include <stdio.h>
int factorial (int num);
int main (void)
{
int i;
for (i = 1; I <= 9; i++)
printf ("%d:%d/n", I, factorial (i));
GetChar ();
return 0;
}
int factorial (int num)
{
if (num = 1)
return (1);
Else
return (num * factorial (num-1));
}
Copy Code code as follows:
Instance: integer to Binary
#include <stdio.h>
void inttobinary (unsigned num);
int main (void)
{
Inttobinary (255); /* 11111111 * *
GetChar ();
return 0;
}
void inttobinary (unsigned num) {
int i = num% 2;
if (num > 1) inttobinary (NUM/2);
Putchar (I? ' 1 ': ' 0 ');
Putchar (' 0 ' + i); /* Can replace the above sentence * *
}
Copy Code code as follows:
Profiling recursion:
#include <stdio.h>
void prn (unsigned n);
int main (void)
{
PRN (1);
GetChar ();
return 0;
}
void prn (unsigned n) {
printf ("%d:%p/n", N, &n); * A * *
if (n < 4)
PRN (n+1); /* B * *
printf ("%d:%p/n", N, &n); /* C * *
}
Example output Effect chart:
Analysis:
The program runs to a, outputting the first line.
At this time n=1, meet the < 4 conditions, continue to execute B start from the call (and then output the second row); Note that statement C has yet to be executed when n=1.
... So the loop, all the way to N=4, A can execute, but not meet the condition B can't execute; At last, N=4 was able to execute C.
But there are four functions in memory waiting to be returned (N=1, 2, 3, 4 o'clock), we call it F1, F2, F3, F4, respectively.
F4 performs C output line fifth, function returns, returns to F3 (at this time n=3), F3 can continue to execute C, output the sixth line.
F3-> F2-> continues C, outputting line seventh.
F2-> F1-> continue C, output the eighth line, execution completed!
In this case, the recursive function is still a lot of memory (sometimes not as direct use of the loop), but it is really clever.