*深入学习函数(3)-- 递归篇(图文详解)

目录

一、什么是递归

                 推荐两个问答社区网站

二、递归的两个必要条件

三、递归练习

                1、接收一个整型值(无符号),按照顺打印它的每一位。输入:1234,输出:1 2 3 4

                2、编写函数不允许创建临时变量,求字符串长度。

四、迭代以及练习

               1、求n的阶乘(不考虑溢出)

               2、求第n个斐波那契数(不考虑溢出)


一、什么是递归

●程序调用自身的编程技巧称为递归。

●递归作为一种算法在程序设计语言中广泛应用,一个过程或函数在其定义或说明中直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相识的规模较小的问题来求解

●只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量

递归的主要思考方式在于:把大事化小。

 为了了解递归,首先写一个史上最简单的递归(会发生错误的递归):

*深入学习函数(3)-- 递归篇(图文详解)_第1张图片

main函数在自己调用自己。但调用着就会发现,程序崩了,它不会一直死递归下去。

同样可以按F10来观察程序

*深入学习函数(3)-- 递归篇(图文详解)_第2张图片

接下来程序就会弹出下面的窗口,stack overflow:栈溢出。这就要牵扯到内存中的栈区、堆区和静态区了。(https://mp.csdn.net/mp_blog/creation/editor/127569715)以往的博客中有细讲

*深入学习函数(3)-- 递归篇(图文详解)_第3张图片

每调用函数,都会为本次函数,在内存的栈区上开辟一块内存空间。

接下来回到刚刚的代码,每调用一次main函数就会在栈区开辟一块内存空间,一直开辟总会有一天把栈区给“榨干”了,这时栈就溢出了。

*深入学习函数(3)-- 递归篇(图文详解)_第4张图片

推荐两个问答社区网站

①(https://stackoverflow.cn/zh-cn)这个网站(国外)相当于一个程序员的问答社区。

②下面的网站叫思否是国内的程序员问答社区
https://segmentfault.com/?u_atoken=f4253b51-aefc-4b63-98f8-9bacecbcd37c&u_asession=01_D58mDxSPeHosldc992SW2dJSe7g4tAfNZtBCDZRWaInKuo59MObn0WcP16k9557X0KNBwm7Lovlpxjd_P_q4JsKWYrT3W_NKPr8w6oU7K9DdwtExMAxsSKcUExmJItvUe3R9QHfzEvknA4dzJmVTGBkFo3NEHBv0PZUm6pbxQU&u_asig=056DBa8BrmTjQT3vz1WFh7_n4TIhIKnCPK8XlNkwPwQB9tVM5jSJ5sVSU-bud6wg3z3v3gBPgQRYOOo0Ag3z7K39D3q3uS2zwSow-0XUFj1eCFpve4R8muC2gXrc4ZShzBH9gxVvi8KyRYwXPTkFBwfb4B0WqgQLp3TT0KCgfA9Cv9JS7q8ZD7Xtz2Ly-b0kmuyAKRFSVJkkdwVUnyHAIJzUNFYcC8iEgq-ihrSinwhXI2Ef-I9PryqZW8BslxiTZDH_8T8uYGNepqxdb-gLe1IO3h9VXwMyh6PgyDIVSG1W9ss1nde6qsjCMZiNfYNgVU6rN4WnkP27a0CQVvwR6dMoVdQ7neKOwcVaOWd5tOnCj9Mmq7zBlclDEIHdVheGprmWspDxyAEEo4kbsryBKb9Q&u_aref=LM2U0pesUMjVOH3Sz9bMZji4E8Y%3Dhttps://segmentfault.com/?u_atoken=f4253b51-aefc-4b63-98f8-9bacecbcd37c&u_asession=01_D58mDxSPeHosldc992SW2dJSe7g4tAfNZtBCDZRWaInKuo59MObn0WcP16k9557X0KNBwm7Lovlpxjd_P_q4JsKWYrT3W_NKPr8w6oU7K9DdwtExMAxsSKcUExmJItvUe3R9QHfzEvknA4dzJmVTGBkFo3NEHBv0PZUm6pbxQU&u_asig=056DBa8BrmTjQT3vz1WFh7_n4TIhIKnCPK8XlNkwPwQB9tVM5jSJ5sVSU-bud6wg3z3v3gBPgQRYOOo0Ag3z7K39D3q3uS2zwSow-0XUFj1eCFpve4R8muC2gXrc4ZShzBH9gxVvi8KyRYwXPTkFBwfb4B0WqgQLp3TT0KCgfA9Cv9JS7q8ZD7Xtz2Ly-b0kmuyAKRFSVJkkdwVUnyHAIJzUNFYcC8iEgq-ihrSinwhXI2Ef-I9PryqZW8BslxiTZDH_8T8uYGNepqxdb-gLe1IO3h9VXwMyh6PgyDIVSG1W9ss1nde6qsjCMZiNfYNgVU6rN4WnkP27a0CQVvwR6dMoVdQ7neKOwcVaOWd5tOnCj9Mmq7zBlclDEIHdVheGprmWspDxyAEEo4kbsryBKb9Q&u_aref=LM2U0pesUMjVOH3Sz9bMZji4E8Y%3D

二、递归的两个必要条件

●存在限制条件,当满足这个限制条件的时候,递归便不再继续。

●每次递归调用之后就会越来越接近这个限制条件

三、递归练习

1、接收一个整型值(无符号),按照顺打印它的每一位。输入:1234,输出:1 2 3 4

解题思路: 

*深入学习函数(3)-- 递归篇(图文详解)_第5张图片

代码实现:

#include 
void Print(unsigned int x)
{
	if (x > 9)  //判断两位数
	{
		Print(x/10);
	}
	printf("%d ", x % 10);
}

int main()
{
	unsigned int  num = 0;
	scanf("%u", &num);//%u - 输入无符号值
	//写一个函数打印num的每一位
	Print(num);
	return 0;
}

画图解释递归:

首先大家要知道,递归其实是两个词,递:递推,归:回归。(很重要!!!)

先递推(黑色),后回归(红色)

*深入学习函数(3)-- 递归篇(图文详解)_第6张图片

2、编写函数不允许创建临时变量,求字符串长度。

首先运行创建临时变量的话,我们应该怎么写呢?

#include 
int ch_len(char* arr)
{
	int count = 0;//计时器
	while (*arr != '\0')
	{
		count++;
		arr++;
	}
	return count;
}


int main()
{
	char arr[] = "hello";
	int ret = ch_len(arr);
	printf("%d\n",ret);
}

代码详解:

*深入学习函数(3)-- 递归篇(图文详解)_第7张图片

 那不允许创建临时变量该怎么写呢?既然讲到了递归,就得用递归来解决

解题思路:

求ch_len(“hello”),如果第一个字符不是'\0',是不是就能转化成1+ch_len(“ello”),接下来ch_len(“ello”)的第一个字符又不是'\0',是不是又能转化成1+1+ch_len(“llo”),接下来以此类推直到'\0'。

代码实现:

int ch_len(char* arr)
{
	if (*arr != '\0')
		return 1 + ch_len(arr + 1);
	else
		return 0;//当碰上第一个字符为\0,就返回0;
}
int main()
{
	char arr[] = "hello";
	int ret = ch_len(arr);
	printf("%d\n",ret);
}

画图解释递归:

先递推(黑色),后回归(红色)

*深入学习函数(3)-- 递归篇(图文详解)_第8张图片

 最后返回了5。

画图不易,请谅解。

如果没看懂后期还会出一个递归的练习。

四、迭代及练习

所谓迭代,就是用非递归来解决问题。 

循环也是一种迭代。

1、求n的阶乘(不考虑溢出)

解题思路:

首先看看递归实现

*深入学习函数(3)-- 递归篇(图文详解)_第9张图片

代码实现:

#include 
int Fac(int n) //形参的名字可以和实参一样
{
	if (n <= 1)
	{
		return 1;
	}
	else
	{
		return n * Fac(n - 1);
	}
}
int main()
{
	int n = 0;
	//输入n的值
	scanf("%d", &n);
	int ret = Fac(n);
	printf("%d\n", ret);
	return 0;
}

老样子,我们画图来分析递归,

递推(黑),回归(红)

*深入学习函数(3)-- 递归篇(图文详解)_第10张图片

 迭代(循环)

#include 
int Fac(int n) 
{
	int i = 0;
	int ret = 1;
	for (i = 1; i <= n; i++)
	{
		ret = ret * i;
	}
	return ret;
}
int main()
{
	int n = 0;
	//输入n的值
	scanf("%d", &n);
	int ret = Fac(n);
	printf("%d\n", ret);
	return 0;
}

2、求第n个斐波那契数(不考虑溢出)

解题思路:

再来看看递归实现

*深入学习函数(3)-- 递归篇(图文详解)_第11张图片

代码实现:

#include 
int Fib(int n)
{
	if (n <= 2)
	{
		return 1;
	}
	else
	{
		return Fib(n-1) + Fib(n - 2);
	}
}
int main()
{
	int n = 0;
	//输入n的值
	scanf("%d", &n);
	int ret = Fib(n);
	printf("%d\n", ret);
	return 0;
}

 画图解析:

递推(黑),回归(红)

*深入学习函数(3)-- 递归篇(图文详解)_第12张图片

 实际上,当输入50时,编辑器的光标还在闪烁,有的人可能会认为程序挂掉了,其实并没有,程序此时此刻还在长时间计算第50个斐波那契数。

所以这题使用递归还存在局限性,那么接下来我们来尝试迭代(循环)

解题思路:

*深入学习函数(3)-- 递归篇(图文详解)_第13张图片

 代码实现:

#include 
int Fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while (n>2) //当n = 1或者2时可以不用算,因为结果都是1,
	{
		c = a + b;
		a = b;
		b = c;
		n--;
	}
	return c;
}
int main()
{
	int n = 0;
	//输入n的值
	scanf("%d", &n);
	int ret = Fib(n);
	printf("%d\n", ret);
	return 0;
}

你可能感兴趣的:(C语言,学习,c语言)