第六章 递归(Recursion)
CH10-递归(Recursion)

If the last-executed statement of a function is a recursive call to the function itself, then this call can be eliminated by reassigning the calling parameters to the values specified in the recursive call, and then repeating the whole function.(可以用循环来完成,修改参数值)
基本的部分(基例)不需要递归)
②A general method that reduces a particular case to one or
more of the smaller cases, thereby making progress toward
eventually reducing the problem all the way to the base case.
Tail Recursion
Hanoi Without Tail Recursion
void move(int count, int start, int finish, int temp) { int swap; // temporary storage to swap towers while (count > 0) { // Replace the if statement with a loop. move(count - 1, start, temp, finish); // first recursive call cout << "Move disk " << count << " from " << start << " to " << finish << "." << endl; count--; // Change parameters to mimic the second recursive call. swap = start; start = temp; temp = swap; } }
递归算法

一.递归算法概述程序调用自身的编程技巧称为递归( recursion)。
一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的能力在于用有限的语句来定义对象的无限集合。
用递归思想写出的程序往往十分简洁易懂。
二.递归算法的特点递归算法是一种直接或者间接地调用自身算法的过程。
在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。
所以一般不提倡用递归算法设计程序。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。
递归次数过多容易造成栈溢出等。
所以一般不提倡用递归算法设计程序。
三.递归算法要求递归算法所体现的“重复”一般有三个要求:一是每次调用在规模上都有所缩小(通常是减半);二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。
四.例子(用从C++描述):行数程序#include <iostream>using namespace std;0 void p (int w){1 if(w>0){2 cout<<w<<" ";3 p(w-1);4 p(w-1);5 }6 }void main(){int a;cin>>a;p(a);}当输入a=4后的打印结果:当p(0)执行完了,就会执行p(1)中的语句5(所以在方格a中,填“5”)。
简述递归思维模式

递归思维模式递归(recursion)是一种常见的问题解决思维模式,它可以将一个大问题划分为更小的子问题,然后通过解决子问题来解决原始问题。
递归在计算机科学中具有广泛的应用,尤其在算法和数据结构中非常常见。
本文将介绍递归思维模式的定义、原理、应用场景、优缺点以及一些实例。
什么是递归思维模式在计算机科学中,递归是一种通过调用自身来解决问题的方法。
递归思维模式基于一个简单的原则:将一个大问题分解为更小的子问题的解决方案。
这种分而治之的思想使得解决问题变得更加简单和可理解。
递归思维模式通常包含两个关键要素: 1. 递归基(base case):是递归过程中最简单的情况,不再需要递归调用,直接返回结果。
2. 递归步骤(recursive step):将原始问题划分为更小的同类子问题,并通过递归调用来解决。
通过这两个要素的组合,递归可以将问题规模不断缩小,直到达到递归基,从而逐步解决问题。
递归原理递归的原理可以通过数学归纳法来理解。
假设我们要证明一个性质对于所有的自然数都成立,我们可以分为两步: 1. 证明基本情况下性质成立,比如证明对于自然数1时该性质成立。
2. 假设该性质对于某个自然数n成立,然后证明对于自然数n+1也成立。
递归的原理与上述过程类似。
首先,我们需要确定递归基,即最简单的情况。
然后,我们假设在解决一个规模为n的问题时,我们已经掌握了解决规模为n-1的子问题的方法。
接下来,我们使用这个假设来解决规模为n的问题。
最后,我们将问题的规模不断缩小,直到达到递归基。
递归的应用场景递归思维模式在很多问题中都有应用,特别是涉及到树结构(如二叉树、图)的问题。
以下是一些递归的应用场景:树的遍历对于树结构,我们可以使用递归思维模式来实现遍历操作,包括前序遍历、中序遍历和后序遍历。
递归的方式非常直观,对于每一个节点,我们先处理它自身,然后递归地处理它的左子树和右子树。
组合和排列问题组合和排列问题在组合数学和算法中经常出现,例如给定一组元素,求出所有的组合或排列的情况。
漫谈递归:循环与迭代

漫谈递归:循环与迭代理清递归、迭代、循环的概念感谢先摘抄“为之漫笔”对这⼏个概念的⼀段:loop、iterate、traversal和recursion这⼏个词是计算机技术书中经常会出现的⼏个词汇。
众所周知,这⼏个词分别翻译为:循环、迭代、遍历和递归。
乍⼀看,这⼏个词好像都与重复(repeat)有关,但有的⼜好像不完全是重复的意思。
那么这⼏个词到底各是什么含义,有什么区别和联系呢?下⾯就试着解释⼀下。
循环(loop),指的是在满⾜条件的情况下,重复执⾏同⼀段代码。
⽐如,while语句。
迭代(iterate),指的是按照某种顺序逐个访问列表中的每⼀项。
⽐如,for语句。
遍历(traversal),指的是按照⼀定的规则访问树形结构中的每个节点,⽽且每个节点都只访问⼀次。
递归(recursion),指的是⼀个函数不断调⽤⾃⾝的⾏为。
⽐如,以编程⽅式输出著名的斐波纳契数列。
有了以上定义,这⼏个概念之间的区别其实就⽐较清楚了。
⾄于它们之间的联系,严格来讲,它们似乎都属于算法的范畴。
换句话说,它们只不过是解决问题的不同⼿段和⽅式,⽽本质上则都是计算机编程中达成特定⽬标的途径。
迭代迭代算法是⽤计算机解决问题的⼀种基本⽅法。
它利⽤计算机运算速度快、适合做重复性操作的特点,让计算机对⼀组指令(或⼀定步骤)进⾏重复执⾏,在每次执⾏这组指令(或这些步骤)时,都从变量的原值推出它的⼀个新值。
利⽤算法解决问题,需要做好以下三个⽅⾯的⼯作:1. 确定迭代变量。
在可以⽤迭代算法解决的问题中,⾄少存在⼀个直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。
2. 建⽴迭代关系式。
所谓迭代关系式,指如何从变量的前⼀个值推出其下⼀个值的公式(或关系)。
迭代关系式的建⽴是解决迭代问题的关键,通常可以使⽤递推或倒推的⽅法来完成。
3. 对迭代过程进⾏控制。
在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。
不能让迭代过程⽆休⽌地重复执⾏下去。
数据结构之递归

数据结构之递归Ⅲ递归的三⼤要素// 算 n 的阶乘(假设n不为0)int f(int n){if(n <= 2){return n;}}第三要素:找出函数的等价关系式第三要素就是,我们要不断缩⼩参数的范围,缩⼩之后,我们可以通过⼀些辅助的变量或者操作,使原函数的结果不变。
例如,f(n) 这个范围⽐较⼤,我们可以让 f(n) = n * f(n-1)。
这样,范围就由 n 变成了 n-1 了,范围变⼩了,并且为了原函数f(n) 不变,我们需要让 f(n-1) 乘以 n。
说⽩了,就是要找到原函数的⼀个等价关系式,f(n) 的等价关系式为 n * f(n-1),即f(n) = n * f(n-1)。
这个等价关系式的寻找,可以说是最难的⼀步了,如果你不⼤懂也没关系,因为你不是天才,你还需要多接触⼏道题,我会在接下来的⽂章中,找 10 道递归题,让你慢慢熟悉起来。
找出了这个等价,继续完善我们的代码,我们把这个等价式写进函数⾥。
如下:// 算 n 的阶乘(假设n不为0)int f(int n){if(n <= 2){return n;}// 把 f(n) 的等价操作写进去return f(n-1) * n;}⾄此,递归三要素已经都写进代码⾥了,所以这个 f(n) 功能的内部代码我们已经写好了。
这就是递归最重要的三要素,每次做递归的时候,你就强迫⾃⼰试着去寻找这三个要素。
还是不懂?没关系,我再按照这个模式讲⼀些题。
有些有点⼩基础的可能觉得我写的太简单了,没耐⼼看?少侠,请继续看,我下⾯还会讲如何优化递归。
当然,⼤佬请随意,可以直接拉动最下⾯留⾔给我⼀些建议,万分感谢!Ⅲ案例1:斐波那契数列斐波那契数列的是这样⼀个数列:1、1、2、3、5、8、13、21、34....,即第⼀项 f(1) = 1,第⼆项 f(2) = 1.....,第 n 项⽬为 f(n) = f(n-1) + f(n-2)。
求第 n 项的值是多少。
《数据结构》第六章 递归 习题

《数据结构》第六章递归习题基本概念题:6-1 什么叫递归?6-2 适宜于用递归算法求解的问题的充分必要条件是什么?什么叫递归出口?6-3 阶乘问题的循环结构算法和递归结构算法哪个的时间效率好,为什么?6-4 非递归函数调用时系统要保存哪些信息?递归函数调用时系统要保存哪些信息?系统怎样保存递归函数调用时的信息?6-5 什么叫运行时栈?什么叫运行时栈中的活动记录?6-6 叙述递归算法的执行过程。
复杂概念题:6-7 推导求解n阶汉诺塔问题要执行的移动操作(即算法中printf()函数的调用)次数。
6-8 我们讨论过的折半查找函数设计如下:int BSearch(elemtype a[], elemtype x, int low, int high){int mid;if(low>high) return -1;mid =(low+high)/2;if(x == a[mid]) return mid;if(x < a[mid]) return (BSearch(a,x,low,mid-1));else return (BSearch(a,x,mid+1,high));}讨论如果把上述折半查找函数中最后两语句改为如下形式能否实现算法的设计要求,为什么?if(x < a[mid]) BSearch(a,x,low,mid-1);else BSearch(a,x,mid+1,high);算法设计题:6-9 要求:(1)写出求1,2,3,......,n的n个数累加的递推定义式;(2)编写求1,2,3,......,n的n个数累加的递归算法,假设n个数存放在数组a中。
6-10 要求:(1)写出求1,2,3,......,n的n个数连乘的递推定义式;(2)编写求1,2,3,......,n的n个数连乘的递归算法,假设n个数存放在数组a中。
6-11 设a是有n个整数类型数据元素的数组,试编写求a中最大值的递归算法。
递归的两个基本要素

递归的两个基本要素
递归的两个基本要素:
(1)边界条件:确定递归到何时终止;(2)递归模式:大问题是如何成为小问题的。
解析:
所谓递归(recursion):
就是子程序(或函数)直接调用自己或间接调用自己的一种基本方法。
运用递归通常可以把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,从而减少程序的代码量。
关于递归的适用情况:
递归通常用来解决结构自相似的问题。
所谓结构自相似,就是说在结构上组成相似的,可以采用同一种方法去解决。
具体地,整个问题的解决,可以分为两部分:第一部分是一些特殊情况,有直接的解法;第二部分与原问题相似,但比原问题的规模小。
实际上,递归就是分而治之的思想,把大问题化为小问题,再把小问题化为更小的问题,在解决这样
一个个的小问题之后,大问题自然迎刃而解。
因此,递归有两个基本要素:
(1)边界条件:确定递归到何时终止,也称为递归出口。
(2)递归模式:大问题是如何分解为小问题的,也称为递归体。
递归函数只有具备了这两个要素,才能在有限次计算后得出结果。
创建树的算法原理

创建树的算法原理
创建树的数据结构的常用算法原理包括:
1. 递归(Recursion)
利用递归函数调用自身的方法创建树的节点。
通过递归不断创建子节点。
2. 迭代(Iteration)
使用循环迭代的方法逐步创建树的每个节点。
利用栈或队列遍历和创建树。
3. 二叉搜索树(BST)
BST要求每个左子树节点小于父节点,每个右子树节点大于父节点。
通过比较不断生成BST。
4. 平衡二叉树(AVL Tree)
通过旋转操作保持树的平衡,左右子树高度差不超过1。
5. 哈夫曼树(Huffman Tree)
根据值的权重不断生成最优二叉树,常用于数据压缩。
6. B树/B+树
利用B树的扩展性来存取和创建大量节点。
7. 空间分割法
通过递归划分空间来生成四叉树或八叉树等。
选择合适的算法可以高效生成并存储树结构,实现各种操作。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
用C语言实现递归
例:用C语言实现递归求阶乘的算法。 语言实现递归求阶乘的算法。 语言实现递归求阶乘的算法
long int fact(int n) { main() int x; { long int y; long int fn; if (n==0) reyurn 1; fn=fact(4); x=n-1; printf(”\nfn=%ld”,fn); y=fact(x); } return(n*y); }
递归的调用过程:
程序执行过程中系统堆栈区的变化:
3*** n x y fact n x y fact
2*** 32** n x y fact
0ห้องสมุดไป่ตู้** 1*** 21** 3*** n x y fact 10** 21** 3*** n x y fact 1011 21** 32** n x y fact
递归不是一种数据结构,而是一种有效的算法设计 注意:递归算法必须是逐步有规律简化的 注意:递归算法必须是逐步有规律简化的,最终要有 逐步有规律简化 调用的情况。 一个非递归的出口,不能出现无穷调用的情况 一个非递归的出口,不能出现无穷调用的情况。
例:阶乘的递推定义
1当n = 0时 n!= n × (n − 1)!当n > 0时
例:Hanoi塔 塔
要求: 1)每次只能移动一个盘子; 2)盘子可以放到ABC任何一个塔座上; 3)任何时候,都不能将较大的盘子压在较小的圆盘之上;
void towers(int n, char Frompeg, char Topeg, char Auxpeg) { char * Format1 = “\n %s %c %s %c”, * MoveDisk1 = “mode disk1 from peg”, * Formatn = “\n %s %d %s %c %s %c”, * MoveDisk = “move disk”, * From = “from peg”, * To = “to peg”; if (n == 1) {printf (Format1, MoveDisk1, Frompeg, To, Topeg); return; // 递归出口 } towers(n-1, Formpeg, Auxpeg, Topeg); printf (Formatn, MoveDisk, n, From, Frompeg, to, Topeg); towers(n-1, Auxpeg, Topeg, Frompeg); }
(1) 4!=4 × 3! ) ! ! 3!=3 ×2! (2) ) ! ! 2!=2 ×1! (3) ) ! ! 1!=1 × 0! (4) ) ! ! (5) ) 0!=1 !
程序实现递归阶乘算法的伪程序
(a) )
(b) ) (c) ) (d) )
if(n= =0) fact = 1;/*定义出口*/ ( ) ; else { x= n - 1; ; 求出y=x!; /*顺序递推求解*/ 求出 !; fact = n * y; /*回溯递推求值*/ ; }
递归的模拟
递归的实现机制
调用函数时: 1)分配函数的数据区; 2)传递参数; 3)把控制权转移给函数, 同时保存返回地址; 系统执行完函数后: a)取得返回地址; b)释放函数数据区; c)把控制权转移到调用函数;
递归函数的执行特点:最先调用的函数,最后被返回。
递归算法的设计
基本要素: 基本要素: 具有某种可借用类同自身的子问题描述的性质。 具有某种可借用类同自身的子问题描述的性质。 类同自身的子问题描述的性质 相对于问题来说,子问题将更加简化。 相对于问题来说,子问题将更加简化。 更加简化 某一有限步的子问题有直接的解存在 某一有限步的子问题有直接的解存在。 有限步
2112 32** n x y fact
3226 n x y fact
n x y fact
折半查找(仅限于有序序列,不妨设为递增序列)
int BSearch (elemtype a[]; elemtype x, int low, int high) { int mid; if (low > high) return -1; mid = (low + high)/2; if (x == a[mid]) return mid; if (x < a[mid]) return BSearch(a, x, low, mid-1); else return BSearch(a,x,mid+1, high); }
数据结构(Data Structure) 数据结构(
第六章 递归 (Recursion) )
递归的概念 用C语言实现递归 递归算法的设计 递归模拟*
递归的概念
定义:一个算法中,若其中有调用自身的过程, 一个算法中,若其中有调用自身的过程, 一个算法中 调用自身的过程 则该算法就是一个递归算法,简称递归。 则该算法就是一个递归算法,简称递归。 自调用) (自调用)
计算斐波那契数列
n, n = 0,1 Fib(n) = Fib (n − 1) + Fib(n − 2), n > 1
long Fib ( long n ) { if ( n <= 1 ) return n; else return Fib (n-1) + Fib (n-2); } 递归的优点:易编程、可读性好、易检验