递归的两种模式

模式一

//递归的过程中在"递"的过程中解决问题
function function_name(Max_argument){if(end_condition){end;}else{solve;function_name(Min_argument);//问题规模逐渐减小}
}

注:位于递归函数前的语句和函数具有顺序性

模式二

//递归的过程中在"归"的过程中解决问题
function function_name(Max_argument){if(end_condition){end;}else{function_name(Min_argument);//问题规模逐渐减小solve;}
}

注:位于递归函数后的语句的执行顺序与原顺序相反;
每一级的递归调用都拥有自己当前的局部变量,所以当调用对象的时候应该注意是调用对象的非引用(复制对象), 以避免修改子对象造成对主问题的影响

调用栈

调用栈:描述函数之间的调用关系,当函数之间相互调用的时候会使用调用栈;
调用栈由多个栈帧组成,每个栈帧记录着一个未运行完的函数; 栈帧中保存着该函数的返回地址以及局部变量;
在递归中,递归函数的每一次的”递进去”,栈帧都会将上个函数的返回地址局部变量保存以便在返回的过程中找得到相应的”回归出来的方向”

通过一个简单的例子说明上述调用顺序问题

//10进制转2进制
void f(int n){if(n==0)return;printf("%d",n%2);//模式1,该模式下输出语句将会是顺序调用f(n/2)
}
//n=4,将输出001,整个过程中先调用printf语句,然后"递进去",通过栈帧进行回归操作最终返回至main函数void f(int n){if(n==0)return;f(n/2)printf("%d",n%2)
//模式2,整个过程中先执行f 函数进行递归,到达递归基时返回执行printf
//整个过程中就是通过栈帧来记录返回过程应该执行的printf,形成"回归出来"解决问题,最终返回至main函数
//n=4,输出100
}

接下来将用斐波那契查找作为典型的例子证明尾递归的重要性:
看下面的一个错误的例子:

#include<iostream>
using namespace std;
int find(int a[],int lo,int hi,int e){int mid=(hi+lo)/2;if(e==a[mid]) return mid;if(e<a[mid]) {cout<<"lo_1="<<lo<<endl;find(a,lo,mid-1,e);}if(e>a[mid]){ find(a,mid+1,hi,e);cout<<"lo_2="<<lo<<endl;}if(lo>hi) {cout<<"lo_3="<<lo<<endl;return 0;  }}
int main(){//0,1,2,3,4,5,6,7,8,9 ,10,11,12,13,14,15,16,17 int a[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18};cout<<find(a,0,17,18);return 0;
}
//斐波那契查找
这个例子证明了尾递归的重要,当前出现的问题是在递归过程中返回值具有随机性,为正确将值返回,记住一条
//递归过程中栈帧的调用,到达递归基的时候返回出正确结果,但是经过栈帧的调用后,正确的返回值返回给上一层调用函数,上一层函数中未寻找到正确的值
//无法返回出正确的值,则返回出去一个随机的值,导致最后答案错误, 正确的做法是将递归过程改为尾递归(return find(....)),直接终止程序(将后续的语句执行停止)
//就此返回出去的值只能是递归基时产生的值(每一层程序终止后所对应的栈帧被清除,最后只保留着递归基中的栈帧)
//原本打算采用else处理,不用return改为尾递归,但是失败了,因为栈栈的缘故,每层的栈帧未清除,并且返回过程中没有满足条件的语句导致没有返回值,最终无法
//完成尾递归的操作
//唉, 理解了递归过程,但是还未深刻理解尾递归的含义,莫大的悲哀,导致出现不该出现的错误 

针对上述的操作进行修改

//斐波那契查找
/*
#include<iostream>
using namespace std;
int f[]={0,1,1,2,3,5,8,13,21,34};
//       0 1 2 3 4 5 6 7 8 9 10
int find(int a[],int lo,int hi,int e){int k=0;while((hi-lo)>f[k]) {//斐波那契数列确定当前的黄金分割点k++;//  cout<<"k"<<k<<endl;} int mid=lo+f[k-2]-1;//在中点求值出现错误,未正确表示中点位置
//  int mid=(lo+hi)>>1; if(lo>=hi) {return 0;}//未命中目标if(e==a[mid]) return mid;if(e<a[mid]) {return    find(a,lo,mid-1,e);}if(e>a[mid]) {return    find(a,mid+1,hi,e);}
}
int main(){//0,1,2,3,4,5,6,7,8,9 ,10,11,12,13,14,15,16,17 int a[]={1,2,3,4,5,6,7,8,9};cout<<find(a,0,9,8);return 0;
} 

递归过程调用栈的使用与调用其他函数没有区别,每一次的函数调用将会形成新的栈帧以保存上一次函数的返回地址和局部变量, 当栈帧中函数体执行完成时将会删除栈帧,处理返回值并修改当前代码行
来自别人的话_很赞同__递归函数尽量不要有返回值或者基本类型的返回值(直接尾递归),如果要求必须有复杂类型返回值,写成两个函数,递归函数不要有返回值,只是在函数中改变复杂类型的值;在驱动程序中定义复杂类型,调用递归函数返回复杂类型

递归过程中语句执行顺序相关推荐

  1. for循环中的三语句执行顺序

    for循环的执行语法是: for(<:初始化>;<条件表达式>;<增量>) 语句: 初始化总是一个赋值语句,它用来给循环控制变量赋初值:条件表达式是一个关系表达式, ...

  2. hmi中的宏指令是c语言,HMI中的宏指令编程中的语句执行顺序是?

    HMI中的宏指令编程中的语句执行顺序是? 以威纶通里的例子为例: 4. if结构语句 macro_command main() int k[10], j for j = 0 to 10 k[j] =  ...

  3. 整理:sql server 中sql语句执行顺序

    原文地址为: 整理:sql server 中sql语句执行顺序 SQL Server 查询处理中的各个阶段(SQL执行顺序) SQL 不同于与其他编程语言的最明显特征是处理代码的顺序.在大数编程语言中 ...

  4. SQL Server 中SQL语句执行顺序

    SQL Server 中SQL语句执行顺序 我们需要对SQL语句的执行顺序了若指掌,才能更好的理解SQL. SQL 不同于与其他编程语言的最明显特征是处理代码的顺序. 在大数编程语言中,代码按编码顺序 ...

  5. mysql limit 执行顺序_SQL语句执行顺序及MySQL中limit的用法

    一. SQL语句执行顺序及MySQL中limit的用法 执行顺序:from... where...group by... having.... select ... order by... limit ...

  6. mysql五补充部分:SQL逻辑查询语句执行顺序

    mysql五补充部分:SQL逻辑查询语句执行顺序一 SELECT语句关键字的定义顺序 二 SELECT语句关键字的执行顺序 三 准备表和数据 四 准备SQL逻辑查询测试语句 五 执行顺序分析 一 SE ...

  7. 关于sql和MySQL的语句执行顺序

    sql和mysql执行顺序,发现内部机制是一样的.最大区别是在别名的引用上. 一.sql执行顺序  (1)from  (3) join  (2) on  (4) where  (5)group by( ...

  8. mysql oracle 查询语句执行顺序_MySQL sql语句执行顺序

    (8)     DISTINCT (1)     FROM (3)      JOIN (2)     ON (4)     WHERE (5)     GROUP BY (6)     HAVING ...

  9. 【转】SQL 语句执行顺序

    From:http://www.jellythink.com/archives/924 Oracle-SQL语句执行原理和完整过程详解:https://wenku.baidu.com/view/398 ...

最新文章

  1. Android 自定义 —— View lineTo 与 rLineTo 的区别
  2. java SAX 防xml注入,如何防止XML注入像XML Bomb和XXE攻击
  3. linux命令之date
  4. 怎么计算一组数据的波动_数据分析(一):数据描述统计
  5. Rsync命令参数详解
  6. redis持久化的几种方式
  7. 第一人称视角的一种解决方案
  8. 1.6 文件上传组件
  9. 垃圾收集器–串行,并行,CMS,G1(以及Java 8中的新增功能)
  10. 前端学习(1232):组件化开发开始
  11. java stream foreach_Java 8 Lambda Stream forEach具有多个语句
  12. JDK1.8版本,java并发框架支持锁包括
  13. 服务器重装系统u盘启动不了怎么办,重装系统时BIOS不识别U盘启动盘怎么办
  14. 神经网络入门(详细 )
  15. virtualxposed使用教程_VirtualXposed框架
  16. Android图片转base64加密在其它平台显示
  17. C语言根号下ln怎么表示,用C语言怎么编y=sin(根号下ax)+ln(a+X)
  18. Navicat导出整个数据库
  19. PQ节点-PV节点-平衡节点
  20. 【爬虫】王者荣耀爬取英雄高清4K图片

热门文章

  1. visio中公式太小_visio绘图中的数据计算
  2. 基本农田卫星地图查询_#重庆朝天门#谷歌百度腾讯高德“卫星地图”PK,谷歌更胜一筹...
  3. 【Python基础入门系列】第07天:Python 数据结构--序列
  4. 元类--用不上的先了解
  5. python中seek函数的用法_在Python中操作文件之seek()方法的使用教程
  6. 立体匹配十大概念综述---立体匹配算法介绍
  7. TeamViewer - 最好用强大的免费跨平台远程桌面控制软件 (支持电脑和手机)
  8. 操作系统:虚拟页式存储管理(缺页中断、页面置换算法)
  9. angularjs的表单验证
  10. UEditor编辑器第一次赋值失败的解决方法