资料:
学校ppt
《计算机算法设计与分析》(第五版)
五分钟学算法
leetcode
递归算法实现机制
一、递归的背景
1、数学中的递归
类似于求解数列的递推公式:
2、生活中的递归
3、有趣的小故事理解递归
从前有座山,山里有座庙的故事
4、计算机中的递归
常见的递归数据结构:单链表、二叉树等
5、递归的重要性
- 递归是程序设计中重要而有效的思想
- 递归是运筹学、决策论和图论等领域的重要内容
- 递归的特点:直观、有效
二、递归的实现机制
1、定义:一个过程直接地或间接地调用自己的过程是递归的过程。
2、递归的实质实际上就是能够把一个大问题分解成比它小点的问题,然后我们拿到了小问题的解,就可以用小问题去构造大问题的解。
子程序实现原理
首先从一般的直接调用一次和n次子程序的形式讨论:
(无嵌套)
(有嵌套)
其次看一下值回传方式:
- 子程序调用时,用栈的方式管理调用子程序时的返回地址。
- 数据传送通过参数或全局变量
- 为子程序的局部变量、形参分配存储空间,并放在栈顶
应该是一个在实参上直接修改,另一个是使用一个新的存储空间,然后把实参值copy过来,在新的存储空间上对原来的实参值进行修改,然后再将修改后的新值赋值给实参。
== 本章讨论的都是采用两次值传送方式==
子程序调用的内部操作
执行调用时相当于先保存下降进程的现场-为上升进程的局部变量开辟空间-传入参数-转入上升进程执行
执行返回操作时先保存到回传变量-弹出地址并返回该地址-回传变量值送到相应位置
递归程序实现原理
还有间接调用,递归出口
绿色的是执行到递归的部分之前执行的函数,黄色部分是到递归出口之后层层返回之后执行的内容,返回到上一个是得在下面黄色部分执行完才能返回到再上一级。
⚠️栈元素由现场信息和参数构成
递归算法设计
一、递归设计需满足的条件
这三点应该时刻铭记!!!
二、递归求解的通用表现形式
1、常见的问题规模和相关参数的表现形式
2、相关解读
- 简单操作即是递归出口将要执行的操作
- call P中参数表反应问题规模的参数应该是down的
- 在call P结束之后会得到规模变小的问题的解和相关信息结合得到的整个问题的解
三、递归的几个典型例子
1、简单的0/1背包问题
㊗️0/1背包问题对于每个物品仅存在两种情况:取:1/不取:0
不能取一部分
⚠️要求是放入背包的质量之和正好为m,所以这个问题要么有解,要么无解
分析过程:
(一)
1、考察物品只有一个的时候背包的容量n=1
2、划分成前n-1个和第n个,如何降低规模
(二)
1、如果第n个物品超过容量,则第n个物品一定不能返回,那么考察范围就缩小到n-1
knap(m,n-1);
这时候knap(m,n-1)的值就是knap(m,n)的值,如果n-1的成功,n也成功
2、如果第n个物品小于容量,也分两种情况
(1)knap(bag-m[n],n-1);
(2)knap(bag,n-1);
也是按照选择还是不选择进行
实现:
#include <iostream>
using namespace std;
bool judge(int bag,int n,int* m);
int main(){
int bag = 20;
int n = 5;
int m[5]={3,5,8,9,10};
cout<<judge(bag, n-1, m)<<endl;
return 0;
}
bool judge(int bag,int n,int* m){
if(bag==m[n])
return true;
if(n>0){
if(bag>m[n]){
if(!judge(bag, n-1, m))
{
return judge(bag-m[n], n-1, m);
}
else{
return true;
}
}
else{
return judge(bag, n-1, m);
}
}
return false;
}
在当前物品的质量小于背包可装的质量时,两种情况有一个if判断,在一个不成功的情况下才选择另外一个执行;而且递归出口是因为每一个物品都有可能整体的放入背包将其装满。
2、棋子移动问题
int main(){
int n;
cout<<"the number of the chess :"<<endl;
cin>>n;
int chess[2*n+1];
for(int i=1;i<=n;i++)
{
chess[i]=0;
chess[i+n]=1;
}
for(int i=1;i<=2*n;i++)
{
cout<<chess[i]<<" ";
}
cout<<endl;
sort(chess,n);
for(int i=1;i<=2*n;i++)
{
cout<<chess[i]<<" ";
}
cout<<endl;
return 0;
}
void exchange(int& a,int& b){
int temp = a;
a=b;
b=temp;
}
void sort(int* chess,int n){
if(n==1)
{
return ;
}
else{
exchange(chess[n+1], chess[2*n]);
exchange(chess[n], chess[2*n-1]);
sort(chess,n-1);
}
}
递归算法的时间复杂性分析
递归的时间复杂性可以直接通过递推公式得到。
时间复杂度:随着自变量的增长,算法所需时间的增长情况
大O表示法表示的是一个算法在worst case的表现情况:
空间复杂度分析
一般书上写的都是:算法运行期间所占用的所有内存空间。