[C Language] Function Recursion

Hello everyone, I am deep fish~ 

Table of contents

1. Explanation of function recursion knowledge

1. What is recursion?

2. Two necessary conditions for recursion

2.1 Exercise 1:

2.2 Exercise 2:

 2. Recursion and iteration

2.1 Exercise 3

2.2 Exercise 4


1. Explanation of function recursion knowledge

1. What is recursion?

A programming technique in which a program calls itself is called recursion

A procedure or function has a method of directly or indirectly calling itself in its definition or description, which usually transforms a large and complex problem layer by layer into a smaller-scale problem similar to the original problem to solve

Recursive strategy: Only a small number of programs can describe the multiple repeated calculations required for the problem-solving process , which greatly reduces the amount of code in the program

The main way of thinking about recursion is: to make big things small

The simplest recursion: the main function calls itself

#include<stdio.h>
int main()
{
	printf("hehe\n");
	main();
	return 0;
}

Code result: print hehe non-stop until the program crashes before exiting

 Q: Then why does the program crash?

Reason: stack overflow The stack has overflowed. For each program, the memory that the stack can use is limited. If the stack space used by the program exceeds the maximum value , a stack overflow will occur and the program will crash.

Although it is a wrong program, the main function in this program does call itself continuously, and then recurses continuously until the stack overflows

2. Two necessary conditions for recursion

There is a constraint condition, when the constraint condition is met, the recursion will not continue

After each recursive call , it keeps approaching this limit

2.1 Exercise 1:

Takes an integer value (unsigned), prints each bit of it in order

For example: input: 1234, output 1 2 3 4

The most common method: let the input number continue to be %10, /10, then save it into the array, and then print each element in the array

Let's take a look at how to write the recursive method :

First of all, the function calls itself, so we have to write a custom function, then we write a Print function to print each bit of the input value on the screen, and then we use the idea of ​​making big things small:

Print(1234)//Continuously simplify, take down one digit each time, until there is only one digit left, then print directly

Print(123)+4

Print(12)+3   +4

Print(1)+2 +3 +4

1+2+3+4

 Code:

#include<stdio.h>
void Print(int n)
{
	if (n > 9)
	{
		Print(n / 10);
	}
	printf("%d ", n % 10);
}
int main()
{
	int num = 0;
	scanf("%d", &num);
	Print(num);
	return 0;
}

Draw pictures to deepen understanding:

Recursion: recursion + regression

(1) If the input value is 1234, when n=1234, if it is greater than 9, it directly enters the if statement, and n/10 enters the next Print function. Note that at this time, printf("%d ", n % 10); statement is not executed,

(2) When entering the next Print function, n=123, enter the if statement again, n/10 enter the next Print function, at this time printf("%d ", n % 10); this statement is still not executed,

(3) When entering the next Print function, n=12, then enter the if statement, n/10 enter the next Print function, at this time printf("%d ", n % 10); this statement is still not executed ,

(4) When entering the next Print function, n=1, skip the if statement directly, and print 1 

But why only 1 is printed at this time?

(5) Because the last line of code was not finished when the Print function was called three times before, that is, the recursion only completed the recursion level, and the regression has not yet been performed. Next, go back and print printf("%d ", n % 10 ); This statement is the process of regression. It may be a little unclear to say it this way. Let’s take a look at the picture again (red represents the process of recursion, and blue represents the process of regression )

 Now let's take a look at what recursion was introduced earlier, and it will be easier to understand. We just merge the repeated parts of the program through the idea of ​​reducing the big things to the small ones, which greatly reduces the amount of code.

When n=123, when the function stack frame is created, we can see that the space for the Print function has been opened up three times, and each call has a space for the Print function call.

 Let's think about another question: Is it okay if the if statement is removed?

Answer: It is definitely not possible. If it is removed, just go in and print the Print function. If you keep recursing, the result will be dead recursion. This is one of the necessary conditions for recursion: restrictions

Another question: Is it okay to change Print(n/10) in the Print function to Print(n)?

Answer: This is also not possible. If n keeps changing, you will always adjust yourself. It is precisely because n is constantly decreasing and recursive that the Print function can continue to return. This is another necessary condition for recursion. : keep approaching the limit condition after each recursive call

2.2 Exercise 2:

Writing a function does not allow the creation of temporary variables, find the length of the string

Let's take a look at the strlen function to find the length of the string: The return type of the strlen function is size_t

size_t is a type, an unsigned integer

size_t is designed for sizeof

Use %zd when printing data of size_t type

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abc";
	size_t len = strlen(arr);
	printf("%zd", len);
	return 0;
}

In fact, this topic is to simulate the realization of the strlen function

(1) The non-recursive method implements the strlen function: we see that a variable count is created when finding the length, which does not meet the meaning of the question

#include<stdio.h>
size_t my_strlen(char* arr)
{
	size_t count = 0;
	while (*arr != '\0')
	{
		arr++;
		count++;
	}
	return count;
}
int main()
{
	char arr[] = "abc";
	size_t len = my_strlen(arr);//这里的arr传递的是数组首元素的地址
	printf("%zd", len);
	return 0;
}

(2) The recursive method implements the strlen function:

Use the idea of ​​making big things small:

my_strlen("abc")

1+my_strlen("bc")

1+1+my_strlen("c")

1+1+1+my_strlen("")

1+1+1+0

 Code:

#include<stdio.h>
size_t my_strlen(char* str)
{
	if (*str != '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}
int main()
{
	char arr[] = "abc";
	size_t len = my_strlen(arr);//这里的arr传递的是数组首元素的地址
	printf("%zd", len);
	return 0;
}

[Reminder]: It is better not to write ++ in function recursion , but to write str+1 directly, because there is a big difference between str++ and ++str, if the recursive part of this code function writes return 1 + my_strlen(str++), The result will not be obtained (because the latter ++ is to assign the value of str first, and then ++, this process is equivalent to the fact that str has not changed, and there is no result); this place should write ++str, but It is not recommended to write this way, it is easy to make mistakes, and if there is a return of str, both of them will be wrong

Drawing analysis:

Recursion:

When str points to a, *str is a, return 1 + my_strlen(str+1), enter the next my_strlen function

The next time you enter the function str points to b, still return 1 + my_strlen(str+1), and continue to enter the next my_strlen function

Then enter the next function str to point to c, or return 1 + my_strlen(str+1), enter the next my_strlen function

This time, enter the function str to point to \0, return 0, and start to return

return:

Return my_strlen(str+1)=0, plus 1 of the penultimate custom function, return 1;

return 1 returns to the previous layer my_strlen(str+1), plus 1 of the penultimate custom function, return 2;

return 2 returns to the previous layer my_strlen(str+1), plus 1 of the penultimate custom function, return 3;

Finally, pass the value of the custom function to the main function and print the result

 2. Recursion and iteration

Iteration is simple to understand: it is a loop

2.1 Exercise 3

Find the factorial of n (without considering overflow)

 In mathematics, n<=1, the factorial is 1; n>1, the factorial is n*Fac(n-1)

5! =5*4! (This simplifies the code so that it does not multiply from 1 to n)

Code:

#include<stdio.h>
int Fac(int n)
{
	if (n <= 1)
		return 1;
	else
		return n*Fac(n - 1);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int r=Fac(n);
	printf("%d", r);
	return 0;
}

But there is still a problem with this code: when the input value is 100, the output result is 0; when the input value is 10000, the stack overflows directly (the reason is that this recursive function has been recursive, but has not returned, consuming a lot of stack space

We can change the above code to iterative (loop) way to improve:

#include<stdio.h>
int Fac(int n)
{
	int i = 0;
	int r = 1;
	for (i = 1; i <= n; i++)
	{
		r = r * i;
	}
	return r;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int r = Fac(n);
	printf("%d\n", r);
	return 0;
}

Although the result obtained by this code will also have errors, there will be no stack overflow

From these two codes, we can find that recursion can actually be replaced by loops, both have advantages and disadvantages

2.2 Exercise 4

Find the nth Fibonacci number (regardless of overflow)

Idea: Mathematical formula

 

 Code:

#include<stdio.h>
int Fbi(int n)
{
	if (n <= 2)
		return 1;
	else
		return Fbi(n - 1) + Fbi(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = Fbi(n);
	printf("%d", ret);
	return 0;
}

But there is still a problem with this code:

When the input number is large, the calculation takes a long time, and it will not come out for a while. For example, if you input 50, it will take a long time to calculate

Let's see how this code calculates:

When you input 50, you need to calculate 49 and 48, and you need to calculate 49 and 47, and you need to calculate 48 and 47 and 46. By analogy, calculating the 50th Fibonacci number requires a lot of calculations, so the program will go For so long, we will find that a number has been repeatedly calculated many times, which wastes a lot of time

But this code does not have a stack overflow :

Although there are so many branches, the depth of recursion is actually only 50, because when calculating the 50th Fibonacci number, first calculate the 49th Fibonacci number. Calculation of a Fibonacci number (that is, the 48th number), and so on, until the leftmost line 50 to 1 is calculated, the depth of recursion is only 50 times, so there will be no stack overflow

 We can change the above code to iterative (loop) way to improve:

In fact, our normal calculation should be calculated from front to back, 1, 1, 2, 3, 5, 8, the addition of the first two numbers equals the third number, and then cycle again, the next cycle needs to add the second number The Bonacci number is regarded as the first number, the third Fibonacci number is regarded as the second number, and the addition is carried out in this way until the number we need is counted, and the loop stops

Code:

[Note]: c should be initialized to 1, otherwise when the input n is 2, the initial value of c will be output directly without entering the loop

#include<stdio.h>
int Fbi(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while (n > 2)
	{
		c = a + b;
		a = b; 
		b = c;
		n--;
	}
	return c;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = Fbi(n);
	printf("%d", ret);
	return 0;
}

The advantage  of this code : fast calculation, no need to repeat calculation

                    Disadvantages: The int type cannot store too large a number, and the number will not fit if it is too large, and the result is wrong

【Summarize】:

If it is easy to think of using recursion and the written code has no obvious defects, then the recursive method can be used; but if there are problems with the recursive method, such as: stack overflow, low efficiency, etc., we still consider using iteration (loop) method to solve the problem, you can also use static static variables to reduce the pressure of insufficient space in the stack area

This is the end of the content of function recursion. For beginners, the content is still difficult to understand, and the topic is also relatively difficult. Some related content will be published in the future: the problem of the Tower of Hanoi, the problem of the frog jumping on the steps, these are all functions Recursion is a typical topic. If you have any questions, please welcome the comment area or private message to communicate. I think the author’s writing is okay, or I have gained a little. Please help me, please give me a one-click triple link, thank you very much!

Guess you like

Origin blog.csdn.net/qq_73017178/article/details/131997526