03 栈与递归 | 数据结构与算法
1. 栈
- 栈的定义:限定在表尾进行插入和删除操作的线性表
- 空栈:不含任何元素的栈
- 栈顶
top
:允许插入删除的一端 - 栈的输入输出序列:给一组互不相同元素的序列,长度为
,出栈入栈可以交替进行,经过栈操作所得到的所有序列的数目为卡特兰数
- 栈的操作(连续设计)
- 置空栈
make_null_stack()
- 判断栈是否为空
empty()
- 入栈
push()
- 出栈
pop()
- 获得栈顶元素
peek()
- 置空栈
- 栈的操作(单链表):当多个栈共享空间时,连续存储已经无法满足空间需要
- 置空栈
make_null_stack()
- 判断栈是否为空
empty()
- 入栈
push()
- 出栈
pop()
- 获得栈顶元素
peek()
- 置空栈
2. 栈的应用
-
进制转换:十进制转
base
进制 -
表达式处理
-
表达式形式
(a + b) * (a - b)
- 前缀表达式:
*+ab-ab
(波兰表达式) - 中缀表达式:
(a + b) * (a - b)
- 后缀表达式:
ab+ab-*
(逆波兰表达式)
- 前缀表达式:
-
中缀表达式求值
- 规则:
在 的前面
+ - * / ( ) # + > > < < < > > - > > < < < > > * > > > > < > > / > > > > < > > ( < < < < < = ) > > > > > > # < < < < < = - 操作
- 操作数栈置空,操作符栈压入
#
(终止符) - 依次读入表达式的每个单词
- 如果是操作数,压入操作数栈
- 如果是操作符,将操作符栈顶元素
与读入的操作符 进行优先级比较- 如果栈顶元素优先级低 , 将
压入操作符栈 - 如果优先级相等 , 弹出
pop()
操作符栈 - 如果栈顶元素优先级高 , 弹出两个操作数,一个运算符,进行计算,并将计算结果压入操作数栈,重复第4步
- 如果栈顶元素优先级低 , 将
- 全部处理完毕,
operator_stack.top() == '#'
- 操作数栈置空,操作符栈压入
- 规则:
-
中缀转为后缀表达式(后缀表达式更利于计算机计算)
- 操作数栈置空,操作符栈压入
#
(终止符) - 依次读入表达式的每个单词
- 如果是操作数,直接输出
- 如果是操作符,将操作符栈顶元素
与读入的操作符 进行优先级比较- 如果栈顶元素优先级低 , 将
压入操作符栈 - 如果优先级相等 , 弹出
pop()
操作符栈 - 如果栈顶元素优先级高 , 弹出
pop()
操作符栈顶元素并且输出,重复第4步
- 如果栈顶元素优先级低 , 将
- 全部处理完毕,
operator_stack.top() == '#'
- 操作数栈置空,操作符栈压入
-
3. 递归
1. 递归基本思想
- 递归调用的定义:子程序(或函数)直接调用自己或者一系列调用语句间接调用自己。是一种描述问题和解决问题的基本方法
- 基本思想:将大问题化为重复的小问题,直至每个小问题都可以得到直接解决
- 算法
- 递归基:最小子问题
- 递归步:通过较为简单的函数值定义一般情况下的函数值
- 适用问题:问题具有某种可借用的类同自身的子问题的描述的性质
- 分类:
- 单路递归:一个递归过程只有一个递归入口
- 多路递归:一个递归过程有多个出口
- 间接递归:函数可以通过其他函数间接调用自己
- 迭代递归:每次递归调用都包含一次循环递归
2. 递归算法实例
- 排列问题
- 有
个元素,编号为 ,用一个具有 个元素的数组A
来存放所生成的排列,然后输出它们 - 分析:
- 递归基:
, 只有一个元素,显然构成排列 - 递归步:
, 如果可由算法perm(A,k-1,n)
完成数组后面k-1
个元素的排列,为完成数组后面k
个元素的排列perm(A,k,n)
,逐一对数组第n-k
元素与数组中第n-k
~n
元素进行互换,每互换一次,就执行一次perm(A,k-1,n)
操作,产生一个排列
- 递归基:
- 算法
- 有
汉诺塔问题- 设
A
,B
,C
是3个塔座。开始时,在塔座A
上有一叠共n
个圆盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为1
,2
,...
,n
,现要求将塔座A
上的这一叠圆盘移到塔座B
上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:- 每次只能移动1个圆盘;
- 任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
- 在满足移动规则1和2的前提下,可将圆盘移至
A
,B
,C
中任一塔座上
- 分析:
- 把
n-1
个盘子移到B
上(通过C
移到从A
移到B
) - 把第
n
个盘子移到C
上 - 把
n-1
个盘子移到C
上 (通过A
移到从B
移到C
)
- 把
- 算法
- 设
3. 函数递归调用的内部执行过程
- 运行开始时,首先为递归调用一个工作 栈 ,其结构包括值参,局部变量与返回地址
- 每次执行递归调用之前,将递归函数的值参和局部变量的当前值以及调用后的返回地址压入栈中
- 每次递归调用结束之后,将栈顶元素弹出栈,是相应的值参和局部变量恢复为调用前的值,然后转向送回返回地址指定的位置继续执行
__EOF__

本文作者:RadiumGalaxy
本文链接:https://www.cnblogs.com/RadiumGalaxy/p/16770197.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/RadiumGalaxy/p/16770197.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
标签:
Courses
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话