目录
3.3栈和队列的应用
3.3.2栈在表达式求值中的应用
【中缀表达式转后缀表达式的过程(2012、2014)】
【栈的深度分析(2009、2012)】
【用栈实现表达式求值的分析(2018)】
3.3.3栈在递归中的应用
【栈在函数调用中的作用和工作原理(2015、2017)】
3.3.5队列在计算机系统中的应用
【缓冲区的逻辑结构(2009)】
【多队列出队/入队操作的应用(2016)】
3.3栈和队列的应用
3.3.2栈在表达式求值中的应用
【中缀表达式转后缀表达式的过程(2012、2014)】
在计算机中,中缀表达式转后缀表达式时需要借助一个栈,用于保存暂时还不能确定运算顺序的运算符。从左到右依次扫描中缀表达式中的每一项,具体转化过程如下:
1) 遇到操作数。直接加入后缀表达式。
2) 遇到界限符。若为“(”,则直接入栈;若为“)”,则依次弹出栈中的运算符,并加入后缀表达式,直到弹出“(”为止。注意,“(”直接删除,不加入后缀表达式。
3) 遇到运算符。若其优先级高于除“(”外的栈顶运算符,则直接入栈。否则,从栈顶开始,依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,直到遇到一个优先级低于它的运算符或遇到“(”时为止,之后将当前运算符入栈。
按上述方法扫描所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式。
例如,中缀表达式 A+B*(C-D)-E/F 转后缀表达式的过程如表 3.1所示。
【栈的深度分析(2009、2012)】
所谓栈的深度,是指栈中的元素个数,通常是给出进栈和出栈序列,求最大深度(栈的容量应大于或等于最大深度)。有时会间接给出进栈和出栈序列,例如以中缀表达式和后缀表达式的形式给出进栈和出栈序列。掌握栈的先进后出的特点进行手工模拟是解决这类问题的有效方法。
【用栈实现表达式求值的分析(2018)】
通过后缀表示计算表达式值的过程:从左往右依次扫描表达式的每一项,若该项是操作数,则将其压入栈中;若该项是操作符<op>,则从栈中退出两个操作数y和x,形成运算指令X<op>Y,并将计算结果压入栈中。当所有项都扫描并处理完后,栈顶存放的就是最后的计算结果。
例如,后缀表达式 ABCD-*+EF/-求值的过程需要 12步,见表 3.2。
3.3.3栈在递归中的应用
【栈在函数调用中的作用和工作原理(2015、2017)】
在递归调用的过程中,系统为每一层的返回点、局部变量、传入实参等开辟了递归工作栈来进行数据存储,递归次数过多容易造成栈溢出等。而其效率不高的原因是递归调用过程中包含很多重复的计算。下面以n=5为例,列出递归调用执行过程,如图3.16所示。
显然,在递归调用的过程中,F(3)被计算2次,F(2)被计算3次。F(1)被调用5次,F(0)被调用3次。所以,递归的效率低下,但优点是代码简单,容易理解。在第5章的树中利用了递归的思想,代码变得十分简单。
可以将递归算法转换为非递归算法,通常需要借助栈来实现这种转换。
3.3.5队列在计算机系统中的应用
【缓冲区的逻辑结构(2009)】
对于第一个方面,仅以主机和打印机之间速度不匹配的问题为例做简要说明。主机输出数据给打印机打印,输出数据的速度比打印数据的速度要快得多,因为速度不匹配,若直接把输出的数据送给打印机打印,则显然是不行的。
解决的方法是设置一个打印数据缓冲区,主机把要打印输出的数据依次写入这个缓冲区,写满后就暂停输出,转去做其他的事情。打印机就从缓冲区中按照先进先出的原则依次取出数据并打印,打印完后再向主机发出请求。主机接到请求后再向缓冲区写入打印数据。这样做既保证了打印数据的正确,又使主机提高了效率。由此可见,打印数据缓冲区中所存储的数据就是一个队列。
【多队列出队/入队操作的应用(2016)】
对于第二个方面,CPU(即中央处理器,它包括运算器和控制器)资源的竞争就是一个典型的例子。
在一个带有多终端的计算机系统上,有多个用户需要 CPU 各自运行自己的程序,它们分别通过各自的终端向操作系统提出占用CPU的请求。操作系统通常按照每个请求在时间上的先后顺序,把它们排成一个队列,每次把 CPU 分配给队首请求的用户使用。当相应的程序运行结束或用完规定的时间间隔后,令其出队,再把 CPU 分配给新的队首请求的用户使用。这样既能满足每个用户的请求,又使 CPU 能够正常运行。