转载来源:https://blog.csdn.net/summer_dew/article/details/82078565?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160082235719195162137781%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=160082235719195162137781&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-2-82078565.first_rank_v2_rank_v25&utm_term=%E5%88%86%E6%B2%BB%E6%B3%95%E9%80%92%E6%8E%A8%E5%85%AC%E5%BC%8F&spm=1018.2118.3001.4187
感谢分享@GeoDoer!!!
文章目录
1. 递归与分治法的区别
1.1 递归
从上往下的分析,然后回溯:从n的情况一直往下走->走到1(特殊情况)->然后往回计算->最终得到n的情况
必须满足:
- 在每一次调用自己时,必须是在某种意义上更接近于解(每次操作是收敛的):问题规模越来越小
- 必须有一次终止处理或计算的准则:必须要有一个出口
1.2 分治法
利用分治法求解,所得子问题的类型常常和原问题相同,因而很自然地使用递归求解
1.2.1 思路
- 输入【规模为n】的函数或问题
- 用某种方法把输入【分割成k(1<k≤n)个子集】,从而【产生l个子问题】
- 再用某种方法把它们【组合成原来问题的解】
1.3 区别
- 递归:是一种算法结构
- 分割求解:是一种算法设计思想
2 递归
2.1 什么情况下用
- 用分割求解设计算法时,子问题和原问题的性质相同
- 问题的当前一步解决之后,余下的问题和原问题性质相同,则自然导致递归求解
2.2 怎么写
- 把大问题,分成几个小问题
- 找到一个特殊情况,那个特殊情况的解是确定的->这个特殊情况就是【基本项】
- 思考每次相同的参数有哪些,将它们写成函数参数->整理出统一形式,即【归纳项】
从上面可以知道,我们需要确定两个东西:
- 基本项:描述一个或几个递归过程的终结状态
【终结状态】出口,特殊情况 - 归纳项:实现从当前状态到终结状态的转化
参数对好了:原问题的参数、子问题的参数要对好
2.3 特点
- 可读性好,但也不要单纯追求形式
- 递归<->利用栈实现的非递归函数(两者可以相互实现)
- 递归函数递归层次的深度决定【所需存储量的大小】
2.4 例题
- 排列组合
- 按顺序入栈的所有可能
3 递归树
分析递归算的工具【递归树】,通过递归树我们可以很清楚的分析递归
例如:
- 递归树的【深度】=递归函数的【递归深度】,而递归深度决定【存储量的大小】
- 递归树上的【结点数目】=函数中的主要【操作重复进行的次数】
3.1 举例
汉诺塔问题
// 将n个盘子从x借助y移动到z
// 例如:move(3,'A','B','Z') 将3个盘子从'A'借助'B'移动到'Z'
void move(int n,char x,char y,char z) {
if (1==n) //只剩下一个盘子
printf("%c-->%c",x,z); //直接从x->z
else {
move(n-1,x,z,y); //将n-1个盘子从x借助z移动到y
printf("%c-->%c",x,z);
move(n-1,y,x,z); //将n-1个盘子从y借助x移动到z
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
通过【递归树】很容易发现:
- 结点数=移动个数
- 中序序列=圆盘移动操作的序列
- 性能:
- 设执行时间为T(n)
- 递归方程为T(n)=2T(n-1)+C
- 初始条件为T(0)=0
3.2 递归怎么分析好不好
以下情况表明【递归函数不适用】该问题
3.2.1 递归树锐化为单支树
【问题】求解:n!
【n!的递归树】
【分析】
- 直线返回
- 递归深度很深,占的存储空间很大
3.2.2 递归树中含有很多相同的结点
【问题】斐波那契数列F[n]=F[n-1]+F[n-2](n>=2,F[0]=0,F[1]=1)
【递归树】
【分析】
- 相同结点很多,不适合用递归
- 这个用递推,从下往上,会容易点
4 递归与递推
- 递归:从上往下,走到最下,再回溯回去,在回溯的过程中计算
- 递推:从下而上,在最下面,计算出最简单的,往上走
【举例】斐波那契数列F[n]=F[n-1]+F[n-2](n>=2,F[0]=0,F[1]=1)
【计算顺序】
F[0]=0,F[1]=1 -> F[2]=F[0]+F[1] -> F[3] -> F[4] -> …
从特殊情况(下)往上递推,每计算一个,就把结果存下来,再往上走
5 递归应用
5.1 斐波那契数列
又名: 兔子数列 黄金分割数列
- 递推公式
F(0)=1
F(1)=1
F(n)=F(n-1)+F(n-2)
- 1
- 2
- 3
- 通项公式
当n趋向于无穷大时,前一项与后一项的比值越来越逼近黄金分割0.618
5.2 杨辉三角
它把二次项系数图形化,把组合数内在的一些代数性质直观地从图形中体现出来。
5.2.1 性质
前提:每行端点与结尾的数为1
基础性质:
- 每行数字左右对称,由1开始逐渐变大
- 第n行的数字有n项
- 第n行数字和为2^(n-1)
- 第n行的m个数可表示为C(n-1,m-1)
- 第n行的第m个数和第n-m+1个数相等,即组合数性质之一
- C(n+1,i)=C(n,i)+C(n,i-1):每个数等于它上方两数之和
不常用的性质:
5. (a+b)^n的展开式中的各项系数依次对应杨辉三角的第(n+1)行中的每一项
6. 将第2n+1行第1个数,跟第2n+2行第3个数、第2n+3行第5个数……连成一线,这些数的和是第4n+1个斐波那契数;将第2n行第2个数(n>1),跟第2n-1行第4个数、第2n-2行第6个数……这些数之和是第4n-2个斐波那契数
5.3 汉诺塔
又名,河内塔
有三根相邻的柱子,标号为A,B,C
A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘
要把所有盘子一个一个移动到柱子B上,并且每次移动同一根柱子上都不能出现大盘子在小盘子上方
请问至少需要多少次移动,设移动次数为H(n)
5.4 八皇后问题
8x8格国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行,同一列,同一斜线上,有多少种摆法