【数据结构与算法】递归

To Iterate is Human,to Recurse,Divine.(人理解迭代,神理解递归) ——L.Peter Deutsch

递归,在数学与计算机科学中,是指在方法的定义中使用方法自身。也就是说,递归算法是一种直接或间接调用自身方法的算法。其中,直接调用自己称为直接递归,而将a调用b,b又调用a的递归叫做间接递归。

简言之:在定义自身的同时又出现自身的直接或间接调用。

注意:递归必须要有一个退出的条件。

递归的数学模型:数学归纳法

数学归纳法适用于将解决的原问题转化为解决它的子问题,而它的子问题又变成子问题的子问题,而且我们发现这些问题其实都是一个模型,也就是说存在相同的逻辑归纳处理项。当然有一个是例外的,也就是归纳结束的那一个处理方法不适用于我们的归纳处理项,当然也不能适用,否则我们就无穷归纳了。总的来说,归纳法主要包含以下三个关键要素:

  • 步进表达式:问题蜕变成子问题的表达式
  • 结束条件:什么时候可以不再使用步进表达式
  • 直接求解表达式:在结束条件下能够直接计算返回值的表达式

递归三要素:

  • 明确递归终止条件(递归出口);
  • 给出递归终止时的处理办法;
  • 提取重复的逻辑,缩小问题规模。

说明:递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。而在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。

引入——斐波那契数列

吼吼,斐波那契数列又被拿来引入啦!

#include<iostream> 
using namespace std;
int Fib(int n) 
{if(n==1||n==2) return 1;elsereturn Fib(n-1)+Fib(n-2);
}
int main()
{int n;cin>>n;cout<<Fib(n)<<endl;return 0;
}

在n>=3时Fib()函数就会自己调用自身

例1.n的阶乘

#include<iostream> 
using namespace std;
int fact(int n) 
{if(n==1||n==0) return 1;elsereturn n*fact(n-1);
}
int main()
{int n;cin>>n;cout<<fact(n)<<endl;return 0;
}

同理。

那么,递归的原理和过程是怎样的呢?

【数据结构与算法】栈中“栈与递归”如下:

函数调用过程

调用前,系统完成:

  1. 将实参,返回地址等传递给被调用函数
  2. 为被调用函数的局部变量分配存储区
  3. 将控制转移到被调用函数的入口

调用后,系统完成:

  1. 保存被调用函数的计算结果
  2. 释放被调用函数的数据区
  3. 依照被调用函数保存的返回地址将控制转移到调用函数
#include<stdio.h>
void fun1(int n){if(n!=0){printf("%d\n",n);fun1(n-1);}
} 
void fun2(int n){if(n!=0){fun2(n-1);printf("%d\n",n);}
}
int main(){fun1(6);printf("\n");fun2(6);return 0;
}

我们继续来看例2

例2.前n项和

输入:n

输出:1+2+3+4+5+…+(n-1)+n的和

我们对这道题很熟悉,很容易就能解出来:

#include<iostream>  
using namespace std;
int main()
{int n,sum=0;cin>>n;for(int i=1;i<=n;i++){sum+=i;}cout<<sum<<endl;return 0;
}

那么,用递归的方法求解是怎样的呢?不妨试一试

【参考程序】

#include<iostream>  
using namespace std;
int sum(int n){if(n==1) return 1;return (sum(n-1)+n);
}
int main()
{int n;cin>>n;cout<<sum(n)<<endl;return 0;
}

递归的过程(可以把递的过程看做”入栈“,归的过程看做”出栈“)

递归1

递归2

例3.汉诺塔

题目描述见【数据结构与算法】递推

汉诺塔1
汉诺塔2

所以可按"n=2"的移动步骤设计:

  1. 若n=0,则结束程序,否则继续往下执行
  2. 用c柱作为协助过渡,将a柱上的n-1片移到b柱上,调用函数mov(n-1,a,b,c);
  3. 将a柱上剩下的一片直接移到c柱上
  4. 用a柱作为协助过渡,将b柱上的n-1片移到c柱上,调用函数mov(n-1,b,c,a);

【参考程序】

#include<iostream> 
using namespace std;
int k=0,n;
void mov(int n,char a,char c,char b){//用b柱作为协助过渡,将a柱上的n片移到c柱上if(n==0) return;//如果n=0,则退出mov(n-1,a,b,c);//用c柱作为协助过渡,将a柱上的n-1片移到b柱上k++;cout<<k<<":from "<<a<<"-->"<<c<<endl;mov(n-1,b,c,a);//用a柱作为协助过渡,将b柱上的n-1片移到c柱上
}
int main()
{cin>>n;mov(n,'a','c','b');return 0;
}

例4.二分查找

设有n个数已经按从大到小的顺序排列,现在输入x,判断它是否在这n个数中,如果存在则输出"YES",否则输出"NO"

当n个数排好序时,用二分查找方法速度大大加快。二分查找算法:

  1. 设有n个数,存放在a数组中,待查找数为x,用L指向数据的高端,用R指向数据的低端,mid指向中间
  2. 若x=a[mid],则输出"YES"
  3. 若x<a[mid],则到数据后半段查找,R不变,L=mid+1,计算新的mid值,并进行新的一段查找
  4. 若x>a[mid],则到数据前半段查找,L不变,R=mid-1,计算新的mid值,并进行新的一段查找
  5. 若L>R都没有查找到,则输出"NO"

该算法符合递归程序设计的基本规律,可以用递归方法设计。

【参考程序】

#include<iostream> 
using namespace std;
int a[101];
void search(int x,int top,int bot){//二分查找递归过程int mid;if(top<=bot){mid=(top+bot)/2;//求中间数的位置if(x==a[mid]) cout<<"YES"<<endl;//找到就输出else{//判断在前半段还是后半段查找 if(x<a[mid]) search(x,mid+1,bot);else search(x,top,mid-1);} } else cout<<"NO"<<endl;
}
int main()
{int k,x,L=1,R;cout<<"输入多少个数?(小于100)"<<endl;cin>>R;cout<<"请输入"<<R<<"个数(从大到小)"<<endl;for(k=1;k<=R;k++){cin>>a[k];} cout<<"请输入要查找的数:"<<endl;cin>>x;search(x,L,R); return 0;
}

当你学了STL后,你可以这样写:

#include<iostream> 
#include<algorithm> 
using namespace std;
int a[101];
int main()
{int k,x,n;cout<<"输入多少个数?(小于100)"<<endl;cin>>n;cout<<"请输入"<<n<<"个数(从大到小)"<<endl;for(k=0;k<n;k++){cin>>a[k];} cout<<"请输入要查找的数:"<<endl;cin>>x;reverse(a,a+n);if(binary_search(a,a+n,x)) cout<<"YES"<<endl;else cout<<"NO"<<endl;return 0;
}

【STL】概述及总结(很全!!!)

例5.集合的划分

集合的划分1
集合的划分2

【参考程序】

#include<iostream>  
using namespace std;
int s(int n,int k){if((n<k)||(k==0)) return 0;//满足边界条件,退出if((k==1)||(k==n)) return 1;return s(n-1,k-1)+k*s(n-1,k);//调用下一层递归 
}
int main()
{int n,k;cin>>n>>k;cout<<s(n,k)<<endl; return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/623143.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySql 安装,小白也可以学会成功安装的保姆级教程

MySql 安装 文章目录 MySql 安装1.Mysql下载1.1 访问下载链接1.2 选择合适版本1.3 下载安装包 2.MySql安装3.安装成功检测验证3.1 mysql自带控制台验证3.2 win系统控制台进入验证 4. mysql 配置path5. navicat 连接 mysql 1.Mysql下载 1.1 访问下载链接 MySQL Downloads 这里…

Spring Boot | SpringBoot对 “SpringMVC“的 “整合支持“、SpringMVC“功能拓展实现“

目录: SpringMVC 的 “整合支持” ( 引入"Web依赖启动器"&#xff0c;几乎可以在无任何额外的配置的情况下进行"Web开发")1.SpringMVC "自动配置" 介绍 ( 引入Web依赖启动器"后&#xff0c;SpringBoot会自动进行一些“自动配置”&#xff0…

eigen使用教程

一 问题集锦 1 fatal error: Eigen/Dense: No such file or directory ubuntu c++使用eigen提示"fatal error: Eigen/Dense: No such file or directory"的解决办法_: fatal error: eigen3/eigen/dense: 没有那个文件或目录 #incl-CSDN博客https://blog.csdn.net/c…

[Collection与数据结构] 二叉树(一):二叉树的性质与基本操作

1. 树形结构 1.1 概念1 (了解) 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。它具有以下的特点&#…

使用剧本批量部署rsync服务端实战

目录 1、实战部署 编写剧本 执行剧本测试&#xff01;&#xff01;&#xff01; 2、部署方式对比 1、实战部署 编写剧本 执行剧本测试&#xff01;&#xff01;&#xff01; 2、部署方式对比 ansible模块实战-部署rsync服务端-CSDN博客 ansible临时命令和playbook区别 …

【UE5.1】使用MySQL and MariaDB Integration插件——(4)修改、插入、删除数据

目录 效果 步骤 一、修改 二、插入、删除 在上一篇博客&#xff08;【UE5.1】使用MySQL and MariaDB Integration插件——&#xff08;3&#xff09;表格形式显示数据&#xff09;基础上继续实现修改、插入和删除数据库数据的功能 效果 修改数据&#xff1a; 插入数据&…

vue 开发 滑动页面中出现tabs 并且需要分页的

效果 需求 我们这个页面顶部有tabs 栏 而且可以滑动到底部 进行分页 实现这样的页面我们应该怎么做 你应该会想到scroll-view 这个组件吧 下面我们来详情介绍一下这个页面的实现和功能开发 首先展示一下代码 item 循环项 <template><div class"wechat-or…

【数据结构与算法】贪心算法及例题

目录 贪心算法例题一&#xff1a;找零问题例题二&#xff1a;走廊搬运物品最优方案问题输入样例例题三&#xff1a;贪心自助餐 贪心算法 贪心算法是一种在每一步选择中都采取当前状态下最优的选择&#xff0c;以期望最终达到全局最优解的算法。它的核心思想是每次都选择当前最…

zabbix监控服务

一、监控软件的作用 作为一个运维&#xff0c;需要会使用监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数据去了解上线发布的结果和网站的健康状态 利用一个优秀的监控软件&#xff0c;我们可以&#xff1a; 对系统不间断实时监控实时反馈系统当前状态保…

2024第十五届蓝桥杯JavaB组省赛部分题目

目录 第三题 第四题 第五题 第六题 第七题 第八题 转载请声明出处&#xff0c;谢谢&#xff01; 填空题暂时可以移步另一篇文章&#xff1a;2024第十五届蓝桥杯 Java B组 填空题-CSDN博客 第三题 第四题 第五题 第六题 第七题 第八题 制作不易&#xff0c;还请点个赞支持…

【软件工程】UML用例图介绍和实例说明

文章目录 1、什么是用例图2、用例图的作用3、怎么画用例图4、三要素说明5、实例说明 1、什么是用例图 用例图&#xff08;Use Case Diagram&#xff09;是统一建模语言&#xff08;UML&#xff09;的一种图&#xff0c;它主要用于描述系统的功能和用户&#xff08;参与者&…

实现智能水控 | 基于ACM32 MCU的分体式水控方案

分体式水控概述 分体式水控是一种常见的水控系统&#xff0c;它的工作原理是通过水的流动来控制水的供应和排放&#xff0c;该系统一般由两部分组成&#xff1a;控制器和水阀。控制器负责监测水的流量和压力&#xff0c;根据设定的参数来控制水阀的开和关&#xff0c;从而实现水…