What is a recursive function/method?
Either method can invoke other methods or call itself, and when this method calls itself, we call it a recursive function or recursive method.
there are usually two characteristics of recursion .:
1. Recursive methods always call themselves until certain conditions are met
2. Recursive methods will have some parameters, and it will pass some of the new parameter values to themselves.
So what is a recursive function? Functions and methods are not fundamentally different, but functions are used only within the class. Previously, only methods in C # had anonymous functions starting with. NET 3.5.
So, we'd better call recursion, not recursive functions, which in this article would be called recursion.
Why do you use recursion in your application? When do I use recursion? How to use?
"Writing any program can be represented by assignment and IF-THEN-ELSE statements, while the while statement can be represented by assignment, If-then-else, and recursion." "(C language Edition) of the data structure Base (Horowitz) of Ellis-Fundamentals of Data Structure in C)
Recursive solutions are convenient and powerful for complex development, but they can cause performance problems (sometimes extremely poor performance) because of the frequent use of the call stack.
Let's take a look at the following figure:
Call stack diagram
Now I'm going to introduce some examples to help you better understand the risks and rewards of recursion.
1. Factorial
Factorial (!) is the product of all positive integers that are less than a number.
0! = 1
1! = 1
2! = 2 * 1! = 2
3! = 3 * 2! = 6
...
N! = n * (n-1)!
The following is an implementation method for calculating factorial (no recursion):
Copy Code code as follows:
public long factorial (int n)
{
if (n = = 0)
return 1;
Long value = 1;
for (int i = n; i > 0; i--)
{
Value *= i;
}
return value;
}
The following is a recursive method for calculating factorial, which is simpler than the previous code.
Copy Code code as follows:
public long factorial (int n)
{
if (n = = 0)//restriction condition, the method calls itself to make a limit
return 1;
return n * factorial (n-1);
}
You know, the factorial of n is actually the factorial of n-1 times N, and N>0.
It can be expressed as factorial (n) = factorial (n-1) * n
This is the return value of the method, but we need a condition
If the n=0 returns 1.
Now the logic of the program should be clear so that we can easily understand it.
2. Fibonacci Series
The Fibonacci sequence is the number listed in the following order:
0,1,1,2,3,5,8,13,21,34,55,... If F0 = 0 and f1= 1 so Fn = Fn-1 + Fn-2
The following method is used to compute the FN (no recursion, good performance)
Copy Code code as follows:
public long Fib (int n)
{
if (n < 2)
return n;
Long[] f = new long[n+1];
F[0] = 0;
F[1] = 1;
for (int i = 2; I <= n; i++)
{
F[i] = F[i-1] + f[i-2];
}
return f[n];
}
If we use recursive methods, this code will be simpler, but with poor performance.
Copy Code code as follows:
public long Fib (int n)
{
if (n = = 0 | | n = = 1)//Meet condition
return n;
Return Fib (k-2) + Fib (k-1);
}
<strong><span style= "Font-size:medium" >3. Boolean combination </SPAN></STRONG>
Sometimes the problem we need to solve is much more complicated than the Fibonacci sequence, for example we want to enumerate all the combinations of Boolean variables. In other words, if n=3, then we must output the following result:
True, True, true
True, True, False
True, False, True
True, False, False
False, True, true
False, True, False
False, False, True
False, False, False if n is large and it is difficult to solve this problem without recursion.
Copy Code code as follows:
public void Compositionbooleans (string result, int counter)
{
if (counter = 0)
Return
bool[] Booleans = new Bool[2] {true, false};
for (int j = 0; J < 2, J + +)
{
StringBuilder StringBuilder = new StringBuilder (result);
Stringbuilder.append (String. Format (' {0} ', Booleans[j]. ToString ())). ToString ();
if (counter = 1)
Console.WriteLine (Stringbuilder.tostring ());
Compositionbooleans (Stringbuilder.tostring (), counter-1);
}
}
Now let's call this method above:
Copy Code code as follows:
Compositionboolean (String. Empty, 3);
Ian Shlasko suggested we use recursion like this .:
Copy Code code as follows:
public void booleancompositions (int count)
{
Booleancompositions (Count-1, "true");
Booleancompositions (Count-1, "false");
}
private void booleancompositions (int counter, string partialoutput)
{
if (counter <= 0)
Console.WriteLine (Partialoutput);
Else
{
Booleancompositions (Counter-1, partialoutput+ ", true");
Booleancompositions (Counter-1, partialoutput+ ", false");
}
}
4. Get inner exception
If you want to get innerexception, then choose the recursive method, it is useful.
Copy Code code as follows:
Public Exception getinnerexception (Exception ex)
{
Return (ex. innerexception = null)? Ex:getinnerexception (ex. innerexception);
}
Why get the last innerexception?! This is not the subject of this article, and our theme is that if you want to get the innermost innerexception, you can do it recursively.
Here's the code:
Copy Code code as follows:
Return (ex. innerexception = null)? Ex:getinnerexception (ex. innerexception);
equivalent to the following code
Copy Code code as follows:
if (ex. InnerException = = null)//Restriction condition
return ex;
Return Getinnerexception (ex. innerexception);//Call yourself with internal exception as parameter
Now, once we get an exception, we can find the innermost innerexception. For example:
Copy Code code as follows:
Try
{
throw new Exception ("This is the Exception",
The new Exception ("This is the the" "the" inner Exception.)
New Exception ("This is the last inner Exception."));
}
catch (Exception ex)
{
Console.WriteLine (ex). Getinnerexception message);
}
I once wanted to write an article about anonymous recursion, but I found that my explanation couldn't go beyond that article.
5. Find Files
I used recursion in the demo project you downloaded, through which you can search for a path and get the path to all the files in the current folder and its subfolders.
Copy Code code as follows:
Private dictionary<string, string> errors = new dictionary<string, string> ();
Private list<string> result = new list<string> ();
private void Searchforfiles (string path)
{
Try
{
foreach (String fileName in Directory.GetFiles (path))//gets all files in the current path
{
Result. ADD (FileName);
}
foreach (String directory in Directory.getdirectories (path))//gets all folders on the current path
{
Searchforfiles (directory);//the methods calls itself with a new parameter, here!
}
}
catch (System.Exception ex)
{
Errors. ADD (Path, ex. Message),//stores Error Messages in a dictionary with path in key
}
}
This method does not seem to satisfy any conditions, because each directory, if there is no subdirectory, will automatically traverse all of the files.
Summary
We can actually use recursion to replace recursion, and performance will be better, but we may need more time overhead and non recursive functions. But the point is that we have to choose the best way to implement the scenario.
Dr. James Macaffrey that we should try not to use recursion unless there is no way. You can read his article.
I think:
A If performance is very important, avoid using recursion
B if the recursive method is not very complex, avoid using recursion
C If A and B are not satisfied, please do not hesitate, use recursion.
For example:
Section I (factorial): Recursion is not complicated here, so avoid recursion.
Section II (FIBONACCI): A recursive merge like this is not recommended.
Of course, I don't mean to belittle the value of recursion, I remember that an important chapter in artificial intelligence has a minimax algorithm (Minimax algorithm), all implemented recursively.
But if you decide to use the team rules method, you'd better try to use storage to optimize it.
Copyright statement: This article by the author Tony Qu original, without the consent of the author must retain this paragraph, and in the article page obvious location to the original connection, otherwise regarded as infringement.