栈的应用
由于栈结构具有的后进先出的固有特性,致使栈成为程序设计中常用的工具。以下是几个栈应用的例子。
一、算术表达式的中缀表示
把运算符放在参与运算的两个操作数中间的算术表达式称为中缀表达式。例如:2+3*4 – 6/9
算术表达式中包含了算术运算符和算术量(常量、变量、函数),而运算符之间又存在着优先级,不能简单地进行从左到右运算,编译程序在求值时,不能简单从左到右运算,必须先算运算级别高的,再算运算级别低的,同一级运算才从左到右。在计算机中进行中缀表达式求值较麻烦。而后缀表达式求值较方便(无须考虑运算符的优先级及圆括号)。
二、算术表达式的后缀表示
把运算符放在参与运算的两个操作数后面的算术表达式称为后缀表达式。
例如,对于下列各中缀表达式:
(1)3/5+8
(2)18-9*(4+3)
对应的后缀表达式为:
(1)3 5 / 8 +
(2)18 9 4 3 + * -
转换规则:把每个运算符都移到它的两个操作数的后面,然后删除掉所有的括号即可.
例如,将中缀表达式a+b*c-d(e*f)转换为后缀表达式.
三、后缀表达式的求值
将中缀表达式转换成等价的后缀表达式后,求值时,不需要再考虑运算符的优先级,只需从左到右扫描一遍后缀表达式即可。具体求值步骤为:从左到右扫描后缀表达式,遇到运算符就把表达式中该运算符前面两个操作数取出并运算,然后把结果带回后缀表达式;继续扫描直到后缀表达式最后一个表达式。
例如,后缀表达式(abc*+def*/-)的求值
四、后缀表达式的求值的算法
设置一个栈,开始时,栈为空,然后从左到右扫描后缀表达式,若遇操作数,则进栈;若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。此时,栈中仅有一个元素,即为运算的结果。
例,求后缀表达式:1 2 + 8 2 - 7 4 - / *的值,
栈的变化情如下:
| 步骤 | 栈中元素 | 说明 |
| 1 | 1 | 1进栈 |
| 2 | 12 | 2进栈 |
| 3 | 遇+号退栈2和1 | |
| 4 | 3 | 1+2=3的结果3进栈 |
| 5 | 38 | 8进栈 |
| 6 | 382 | 2进栈 |
| 7 | 3 | 遇-号退栈2和8 |
| 8 | 36 | 8-2=6的结果6进栈 |
| 9 | 367 | 7进栈 |
| 10 | 3674 | 4进栈 |
| 11 | 36 | 遇-号退栈4和7 |
| 12 | 36 | 7-4=3的结果3进栈 |
| 13 | 3 | 遇/号退栈3和6 |
| 14 | 32 | 6/3=2的结果2进栈 |
| 15 | 遇*号退栈2和3 | |
| 16 | 6 | 3*2=6进栈 |
| 17 | 6 | 扫描完毕,运算结束 |
从上可知,最后求得的后缀表达式之值为6,与用中缀表达式求得的结果一致,但后缀式求值要简单得多。
五、中缀表达式变成等价的后缀表达式的算法
将中缀表达式变成等价的后缀表达式,表达式中操作数次序不变,运算符次序发生变化,同时去掉了圆括号。转换规则是:设立一个栈,存放运算符,首先栈为空,编译程序从左到右扫描中缀表达式,若遇到操作数,直接输出,并输出一个空格作为两个操作数的分隔符;若遇到运算符,则必须与栈顶比较,运算符级别比栈顶级别高则进栈,否则退出栈顶元素并输出,然后输出一个空格作分隔符;若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止。当栈变成空时,输出的结果即为后缀表达式。将中缀表达式(1+2)*((8-2)/(7-4))变成等价的后缀表达式。
现在用栈来实现该运算,栈的变化及输出结果如下:
| 步骤 | 栈中元素 | 输出结果 | 说明 |
| 1 | ( | (进栈 | |
| 2 | ( | 1 | 输出1 |
| 3 | (+ | 1 | +进栈 |
| 4 | (+ | 1 2 | 输出2 |
| 5 | 1 2 + | +退栈输出,退栈到(止 | |
| 6 | * | 1 2 + | *进栈 |
| 7 | *( | 1 2 + | (进栈 |
| 8 | *(( | 1 2 + | (进栈 |
| 9 | *(( | 1 2 + 8 | 输出8 |
| 10 | *((- | 1 2 + 8 | 输出2 |
| 11 | *((- | 1 2 + 8 2 | - 进栈 |
| 12 | *( | 1 2 + 8 2 - | -退栈输出,退栈到(止 |
| 13 | *(/ | 1 2 + 8 2 - | / 进栈 |
| 14 | *(/( | 1 2 + 8 2 - | ( 进栈 |
| 15 | *(/( | 1 2 + 8 2 - 7 | 输出7 |
| 16 | *(/(- | 1 2 + 8 2 - 7 | -进栈 |
| 17 | *(/(- | 1 2 + 8 2 - 7 4 | 输出4 |
| 18 | *(- | 1 2 + 8 2 - 7 4 - | -退栈输出,退栈到(止 |
| 19 | * | 1 2 + 8 2 - 7 4 - / | /退栈输出,退栈到(止 |
| 20 | 1 2 + 8 2 - 7 4 - / * | *退栈并输出 |
1、 数制转换
将一个非负的十进制整数N转换为另一个等价的基为B的B进制数的问题,很容易通过"除B取余法"来解决。
【例】将十进制数13转化为二进制数。
解答:按除2取余法,得到的余数依次是1、0、1、1,则十进制数转化为二进制数为1101。
分析:由于最先得到的余数是转化结果的最低位,最后得到的余数是转化结果的最高位,因此很容易用栈来解决。
转换算法如下:
typedef int DataType;//应将顺序栈的DataType定义改为整型
void MultiBaseOutput (int N,int B)
{//假设N是非负的十进制整数,输出等值的B进制数
int i;
SeqStack S;
InitStack(&S);
while(N){ //从右向左产生B进制的各位数字,并将其进栈
push(&S,N%B); //将bi进栈0<=i<=j
N=N/B;
}
while(!StackEmpty(&S)){ //栈非空时退栈输出
i=Pop(&S);
printf("%d",i);
}
}
|
2、 栈与递归
|
1306

被折叠的 条评论
为什么被折叠?



