递归和非递归
能采用递归解决的问题通常具有以下特征
规模为
递归树、剪枝、记忆化不再赘述
分治思想
把一个规模比较大的问题分解为一个或若干规模比较小的问题,分别对这些较小的问题求解,再综合它们的结果,从而得到原问题的解。这些比较小的问题的求解方法与原来问题的求解方法一样
- 分解
- 解决
- 合并
时间复杂度分析
设一个分治算法将规模
则
点击查看证明
容易知道
当
则
记
则
则
由于
根据对数性质
当
当
当
Strassen 矩阵乘法
算法思想
将两个
每个子块为
传统的分块乘法需要 8 次子矩阵乘法:
Strassen 的关键是构造 7 个“辅助乘积”
然后恢复结果子块为:
这样每一层递归只需要
复杂度分析
设 Strassen 在大小
应用上面的定理:
令
因此有递推式:
目前最新进展已经到
Matrix multiplication - Wikipedia
递归与非递归
递归缺点:
- 有栈空间溢出的风险
- 堆栈空间以及函数调用造成较大的时间与空间开销
但是这不代表代码执行效率低,相反,有时递归比非递归快,两者实际是相当的
Hanoi 塔的非递归实现
写出 Hanoi(n,A,B,C) 的递归树,进行树的先序遍历,仿照系统栈的方式实现递归
非递归实现1:与递归树等价的非递归实现
1 | struct node{ |
其他的实现方式
和递归树不等价
1 | void hanoi2(int N, char a, char b,char c){ |
定义三根柱子为
第
**起点柱子函数 **
终点柱子函数
汉诺塔问题的盘子移动顺序存在规律:
- 第
个盘子每隔 步移动一次; - 最小盘子移动规律最简单,次小盘子次之。
- 第
利用位运算:
可以计算第 步移动的盘子编号; 可以确定该盘子目标位置的循环规律。
最终公式:
1 | inline int f(int x){return(x&x - 1)%3;} |
1 | _hanoi: # void hanoi(int N, char a, char b, char c) |
1 | void hanoi4(int N, char a, char b, char c) { |
递归消除
尾递归
递归调用处于递归过程的最后一条语句的情况
1 | int f(int n){ |
改为
1 | int f(int n){ |
线性递归
线性递归函数的最后一步不是递归操作,而是其他操作
1 | void example(int n){ |
根据系统栈的调用,改为
1 | void example(int n){ |
Hanoi 塔的拓展
- Title: 递归和非递归
- Author: exdoubled
- Created at : 2025-10-15 17:00:00
- Updated at : 2025-10-22 10:37:54
- Link: https://github.com/exdoubled/exdoubled.github.io.git/sjjg/sjjg04/
- License: This work is licensed under CC BY-NC-SA 4.0.