in the Infinite Classification of PHP, many of the methods used are recursive, but our understanding of recursion is still very vague, we will then understand the advantages and disadvantages of recursion, so that we can have a comprehensive understanding.
What is recursion?
Defined
Recursion (English: recursion), also translated as recursion, in mathematics and computer science, refers to the method of using the function itself in the definition of a function.
The English recursion from the etymology is only "re-(again)" + "curs-(Come, happen)" is the repetition of the meaning of recurrence. and the corresponding Chinese translation "recursion" but expressed two meaning: "Hand" + "return". These two meanings are the essence of recursive thinking. On this level, Chinese translation is more expressive.
See a metaphor on the Internet:
Suppose you are in a movie theater, you want to know which row you are sitting in, but there are a lot of people ahead, you don't bother to count, so you ask the previous row of people, "which row are you sitting in?" "So that the people in front (code a) answer you, you will know what row you are in--just add a to the answer, is your own platoon." Behold A is more lazy than you, he also did not want to count, so he also asked him in front of the person b"you sit in which row? "So that A can use the exact same steps as you to know your platoon." Then B does the same. Until they had this bunch of people asking the front row, the first row of people told the question to the person "I'm in the first row." In the end, everyone knows what row they are in.
The difference with the cycle
Looking at the definition of the wiki above, it looks like the usual infinite cycle of death, what is the difference between them?
Recursion is static and there is a return.
The loop is static and dynamic, and there is no return.
For example, give you a key, you stand in front of the door, asking you to use this key to open a few doors.
Recursion: You open this door in front of you, see there is a door in the room (the door may be the same size as the front door open (static), or the door is smaller (moving)), you walk over, found that the key can also open it, you push the door, found there is a door, you continue to open, ... , after a few times, you open a door in front of you, found that there is only one room, there is no door. You start on the way back, every time you walk back to a house, you count once and walk to the entrance, and you can answer the question of how many doors you opened with the key.
Loop: You open the door in front of you, see there is a door in the house, (this door may be the same size as the front door open (static), it may be a little bit smaller (moving)), you walk over, found that the key can also open it, you push the door, found there is a door, (front door if the same, the door is the same, If the second door becomes smaller than the first one, the door becomes smaller than the second door (as if it were not changed or the same change), and you continue to open the door ... , has been going on like this. The people at the entrance are always waiting for you to go back and tell him the answer.
Recursive thinking
Recursion is having to go (pass) back (return).
Specifically, why is it possible to "go there"?
This requires the problem of recursion to be able to answer similar but slightly different questions with the same problem (the key in the example above can open the lock on the back door).
Why can "have back"?
This requires that these problems continue from large to small, from near and far in the process, there will be an end point, a critical point, a baseline, a you go to that point you do not have to move to a smaller, farther place, and then start from that point, the original road back to the origin.
The basic idea of recursion is to transform large-scale problems into small-scale similar sub-problems to solve. When a function is implemented, because the method of solving the big problem and the method of solving the small problem are often the same method, it produces the case that the function calls itself. In addition, the problem-solving function must have an obvious end condition, so that no infinite recursion can occur.
When do I need to use recursion?
When the definition of some problems is in itself recursive form, it is most suitable to be solved by recursion.
Computer majors are most familiar with the definition of "tree" [4,5]. There are some definitions, such as factorial, Fibonacci series [6], and so on. Using recursion to solve these problems, often a few lines of code will take care of some seemingly "scary" problems. Of course, the performance of recursion is another matter, the allocation of stacks, the cost of function calls are in specific engineering practice to consider. But now just to discuss the idea of recursion, you might as well let go of those, appreciate the beauty of recursion.
Recursion simplifies the way we think when it comes to solving certain problems, and the code is more refined and easier to read. So since recursion has so many advantages, are we going to solve all the problems by hand? Is there no drawback to recursion? Today we are going to discuss the shortcomings of recursion. When it comes to recursion, it has to face its efficiency problems.
Why is the efficiency of recursion inefficient?
Let's take the Fibonacci (Fibonacci) sequence as an example. In many textbooks or articles where recursion or computational complexity is involved, the procedure for calculating the Fibonacci sequence is used as a classic example. If you now want to write a function that calculates the nth number of Fibonacci numbers in C # as quickly as you can (regardless of exceptions such as a parameter less than 1 or a result overflow), I wonder if your program will resemble the following code:
public static ULONG Fib (ulong N) { return (n = = 1 | | n = = 2)? 1:fib (n-1) + Fib (n-2);}
This code should be short (only one line of code execution), visually clear, and very much in line with the code aesthetics of many programmers, many people write such code in the interview may be in the heart of cool. But if you use this code to try to calculate the FIB (1000) I think it will not be good again, its running time may make you mad.
It seems that good-looking code may not be used, if the program in efficiency can not accept the beautiful God horse is a floating cloud. If you simply analyze the execution flow of the program, you will find out where the problem is, and calculate Fibonacci (5) as an example:
As you can see, in the process of calculating the FIB (5), the FIB (1) calculates twice, the FIB (2) calculates 3 times, the FIB (3) calculates two times, and the task that can be done with only 5 calculations is calculated 9 times. This problem is becoming more apparent as the scale increases, so that fib (1000) is no longer available for the time being.
We were using a simple definition to find FIB (n), that is, using the formula FIB (n) = fib (n-1) + fib (n-2). The idea is very easy to think of, but after careful analysis we find that when we call FIB (n-1), we also call FIB (n-2), which means that fib (n-2) calls two times, the same reason, F (n-3) is called two times when I call F (n-2). And these redundant calls are completely unnecessary. The complexity of the algorithm can be calculated by means of a number of levels.
Improved Fibonacci recursion algorithm
So is there a better recursive algorithm for calculating Fibonacci sequences? Of course. Let's take a look at the first few items of the Fibonacci sequence:
11, 1, 2, 3, 5, 8, 13, 21, 34, 55 ...
Notice that if we get rid of the previous item, the resulting sequence will still satisfy f (n) = f (n-1) –f (n-2), and we get a sequence of 1, 2. It is easy to see that the first n-1 of this sequence is the nth of the original sequence. How do you know how we're going to design the algorithm? We can write a function that accepts three parameters, the first two of which are the beginning of the sequence, and the third is the first of the series we want to ask for the first two arguments.
1int fib_i (int A, int b, int n);
Inside the function we first check the value of n, if n is 3 we simply return to A+b, which is a simple scenario. If n>3, then we call F (b, a+b, n-1), so we narrow down the size of the problem (from the nth item to the first n-1). OK, the final code is as follows:
int fib_i (int a, int b, int n) { if (n = = 3) return a+b; else return fib_i (b, A+b, n-1);}
Why is there a lot of overhead on memory?
The principle of recursion is that the value of the variable to be computed is stored on the stack, looped sequentially until the recursive end condition is satisfied, and the value of the variable to be computed is fetched from the stack, and the final result is computed.
Make a metaphor: Calculate 10! =
Recursive words, process: 10! =10 * 9!
9!=9 * 8!
......
2! =2 *1!
1! =1
When calculating, it is to save an expression to memory until the recursive condition satisfies 1! =1, and then take out the existing expression from memory, and draw the final result. In this way, more system resources will be expended.
And the system sets the maximum recursion depth. If the depth is greater than the error, exit. function recursive call process, the function of the parameters, return value, etc. will not stop pressure stack. function calls will continue to use the stack, report to the site, restore the scene, so the memory overhead will be more and more large, the solution is for the tail recursion, but, PHP is not optimized for tail recursion, so this solution has no practical significance.