【C语言】带你玩转递归,迭代算法2

简介: 【C语言】带你玩转递归,迭代算法

四.递归与迭代

递归,就是在运行的过程中调用自己。

迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。

迭代算法是用计算机解决问题的一种基本方法,一般用于数值计算。累加、累乘都是迭代算法的基础应用

斐波那契数列

1.递归求解

下边我们通过求斐波那契数列的例子来具体讲解一下。

在咱们开始之前我们先来讲讲什么是斐波那契数列

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

1 1 2 3 5 8 13 21 34 55 …

每前2个的数的和是第三个数,我们把拥有这种性质的数列称为斐波那契数列。


//求第n个斐波那契数
//1 1 2 3 5 8 13 21 34 55 ...
int fib(int n)
{
  if (n <= 2)
    return 1;
  else
    return fib(n - 1) + fib(n - 2);
}
int main()
{
  int n = 0;
  scanf("%d", &n);
  int ret = fib(n);
  printf("%d ", ret);
}

示例结果

4bb6b1f3fbeb4971bb90fc20fb8aefa9.png

这里的图解我希望大家能自己画一下,如果你理解了上面我讲的那两个例子这对你来说应该不算很难。

递归算法的不足

我们重点先讲讲上面这段代码中出现的问题

输一个很小的数我们这个程序能完美的运行,可输入一个很大的数呢?

我们来测试一下:

15bd8aae63604908904592d9c4a3adec.png

没有任何结果,这是为什么呢?

我们现在想测试一下此时该函数被执行了几次

int count = 0;//全局变量
int fib(int n)
{
  if (n == 3)
    count++;
  if (n <= 2)
    return 1;
  else
    return fib(n - 1) + fib(n - 2);
}
int main()
{
  int n = 0;
  scanf("%d", &n);
  int ret = fib(n);
  printf("%d\n ", ret);
  printf("n等于3执行了%d次 ", count);
}

abe7826b06a24b3883b87fbd61d3eaf3.png


当n=30时,仅仅是n=3这一种情况就被执行了30多万次,可见我们这个函数的时间复杂度有多大。

为什么会出现上述情况呢?

画图说明一下

3f81d506ae6b4d55998ded4b1579d627.png

图画的太丑辣,大家能理解我的意思就行

我们发现 fib 函数在调用的过程中很多计算其实在一直重复,这就导致我们的程序中出现的大量的重复没必要的计算浪费时间。

同时:

在调试 factorial 函数的时候,如果你的参数比较大,那就会报错: stack overflow(栈溢出)这样的信息。

系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为栈溢出

2.使用迭代算法改进我们的代码

1.将递归改写成非递归。

2.使用 static 对象替代 nonstatic 局部对象。

在递归函数设计中,可以使用 static 对象替代nonstatic 局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放nonstatic 对象的开销,而且 static 对象还可以保存递归调用的中间状态,并且可为各个调用层所访问

这里对关键字static不太了解的,可以看看下面链接中的博客,在操作符部分有具体讲static的用法:【C语言初阶】万字解析,带你0基础快速入门C语言(下)

改进代码如下:

//求第n个斐波那契数
int fib(int n)
{
  int result;
  int j;
  int i;
  result = j = 1;
  while (n > 2)
  {
    n -= 1;
    //实现每一次n减小时新的n-1与n-2并赋值给n
    i = j;//把n-1的值给n-2
    j = result;//把此时n的值给n-1
    result = i + j;//n的值等于此时的(n-1)+(n-2)
  }
  return result;
}
int main()
{
  int n = 0;
  scanf("%d", &n);
  int ret = fib(n);
  printf("%d\n ", ret);
}

看看现在的结果


6fb79b6054854336b27e2eb5f6ecf995.png

这里由于int型能存放的数不够肯定栈溢出了,但是先别管结果对不对,你就说快不快吧,是不是能给你个结果?这意味着咱们把代码重复冗杂的问题解决了!

a6f96a23b44e4665a0b382d216d3e080.png

提示:

1. 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。

2. 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。

3. 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销


这里还有几个经典的问题比如汉诺塔和青蛙跳台阶,后面都会有具体博客去讲的。


五.扫雷游戏中的递归

另外,在改进扫雷游戏中我们也使用了递归算法,但是那个比较复杂,我也在扫雷游戏那篇博客里具体讲了,感兴趣的可以去看看,链接就放在这里啦!

【C语言】万字教学,带你分步实现扫雷游戏(内含递归函数解析),剑指扫雷,一篇足矣

总结

以上就是今天的所有内容了,今天我们具体分析的递归算法和迭代算法,同时对比了他们之间的区别与优缺点。

如果你有任何疑问欢迎在评论区指出或者私信我,我看到后会第一时间回复的哦!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!


(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)


20fa3306e76244de9879742c165c792a.gif

目录
相关文章
|
19天前
|
存储 编译器 C语言
爱上C语言:函数递归,青蛙跳台阶图文详解
爱上C语言:函数递归,青蛙跳台阶图文详解
|
18天前
|
算法
算法系列--递归(一)--与链表有关(上)
算法系列--递归(一)--与链表有关
27 0
|
4天前
|
算法
数据结构与算法-递归思想
数据结构与算法-递归思想
6 0
|
5天前
|
机器学习/深度学习 C语言
函数递归深入解析(C语言)
函数递归深入解析(C语言)
|
7天前
|
算法 搜索推荐 C语言
C语言用流程图表示算法
C语言用流程图表示算法
14 0
|
8天前
|
C语言 索引
c语言的函数与递归
c语言的函数与递归
14 1
|
14天前
|
缓存 算法 Python
python算法对音频信号处理Sonification :Gauss-Seidel迭代算法
python算法对音频信号处理Sonification :Gauss-Seidel迭代算法
10 0
|
19天前
|
搜索推荐 C语言 C++
【排序算法】C语言实现归并排序,包括递归和迭代两个版本
【排序算法】C语言实现归并排序,包括递归和迭代两个版本
|
10天前
|
机器学习/深度学习 人工智能 算法
基于DCT和扩频的音频水印嵌入提取算法matlab仿真
本文介绍了结合DCT和扩频技术的音频水印算法,用于在不降低音质的情况下嵌入版权信息。在matlab2022a中实现,算法利用DCT进行频域处理,通过扩频增强水印的隐蔽性和抗攻击性。核心程序展示了水印的嵌入与提取过程,包括DCT变换、水印扩频及反变换步骤。该方法有效且专业,未来研究将侧重于提高实用性和安全性。
|
25天前
|
机器学习/深度学习 算法
【MATLAB】GA_BP神经网络时序预测算法
【MATLAB】GA_BP神经网络时序预测算法
33 8