栈
括号匹配问题
- 基本想法:最后出现的左括号最先匹配
- 不匹配的情况:
- 左右括号不匹配
- 左括号单身(最后栈不为空)
- 右括号单身(栈空但是还有右括号)
表达式计算
基本概念
按照操作符与操作数的相对位置分成三种计算方式:
- 后缀表达式(逆波兰表达式):操作符在两个操作数的后面
- 前缀表达式(波兰表达式):操作符在两个操作数的前面
- 中缀表达式:操作符在两个操作数的中间
表达式转化
将在中缀表达式中参与运算的两个数,按照相对于操作符的位置称为左操作数和右操作数。当出现优先级别相同的多个运算时,按照先后计算的顺序不同,转化后的表达式不唯一。但是计算机在进行转化时只有一种结果:
- 中缀表达式转后缀表达式的原则:左优先原则,只要左边的运算符能够计算出结果,就优先算左边的。转化后的表达式利用栈计算时,先出栈的是右操作数。
- 中缀转前缀实行右优先,前缀表达式先出栈的是左操作数
表达式求值(算法实现)
-
用栈实现中缀表达式转后缀表达式:
初始化一个栈,用于保存暂时还不能确定运算顺序的运算符。 从左到右处理各个元素,直到末尾。可能遇到三种情况:
(1) 遇到操作数。直接加入后缀表达式。
(2)遇到界限符。遇到“(”直接入栈;遇到“)”
则依次弹出栈内运算符并加入后缀表达式,直到弹
出“(”为止。注意: “(”不加入后缀表达式。
(3)遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符
,并加入后缀表达式, 若碰到“(”或栈空则停止。之后再把当前运算符入栈。按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式。
-
用栈实现后缀表达式的计算:
(1)从左往右扫描下一个元素,直到处理完所有元素
(2)若扫描到操作数则压入栈,并回到(1); 否则执行(3)
(3)若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到(1) -
用栈实现中缀表达式的计算:
初始化两个栈,操作数栈和运算符栈
若扫描到操作数,压入操作数栈
若扫描到运算符或界限符,则按照中缀转后缀相同的逻辑压入运算符栈(期间也会弹出运算符,每当弹出一个运算符时,就需要再弹出两个操作数栈的栈顶元素并执行相应运算,运算结果再压回操 作数栈)
栈递归应用
函数调用特点:最后被调用的函数最先执行完成。
函数调用时,函数调用栈可称为"递归工作栈", 没进入一层递归,就将递归调用所需信息压入栈顶;每退出一层递归,就从栈顶弹出相应的信息。
递归层数过多时,可能发生栈溢出
。递归通过栈实现,因此占用空间会随着递归深度的增加而增加。并且可能包含重复计算。
递归算法:可以将原始问题转化成属性相同但是规模更小的问题
递归的两个主要成分:
- 递归表达式,
- 边界条件
队列的应用
树的层次遍历
从根节点开始,将其加入队列中,当要处理该节点时,弹出并访问该节点,扫描其孩子节点,并将其孩子节点加入队列。如此进行下去直到遍历完所有节点。
图的广度优先遍历
将要处理的节点存入队列中,对于要处理的节点,检查与其相邻的节点中是否有未处理的节点,如果有将其添加到队列中,然后处理该节点并将该节点从队列中移除。如此进行下去直到遍历完所有节点。
在操作系统中的应用
多个应用申请有限资源的使用,按照先来先使用的原则