概念
栈Stack:栈顶插入或者删除,栈底不变
基本操作:入栈push,出栈pop
按照存储方式分类
- 顺序存储:顺序栈
- 链式存储:链栈
中缀表达式和后缀表达式
定义:
比如:2*(9+6/3-5)+4=???
这个算数表达式先算括号里的,再算括号里的除法,再算...总之就是存在优先级
这样的表达式就叫做中缀表达式,也叫算术表达式,算出来是16
而计算机如果要计算2*(9+6/3-5)+4,如果也像人一样,先算...,再算...的中缀表示式,程序设计?就很麻烦!!!
计算机用的是,后缀表达式
刚才的表达式对计算机来说是这样存储的:2963/+5-*4+
计算机对“2963/+5-*4+”的计算方法:
建立一个栈S ,左到右读后缀表达式,
读到数字就将它转换为数值压入栈S中,
读到运算符则从栈中依次弹出两个数分别到X和Y,
然后以“Y 运算符 X”的形式计算机出结果,
再压加栈S中 ,果后缀表达式未读完,就重复上面过程,最后输出栈顶的数值则为结束。
- S:2;
- S:2、9;
- S:2、9、6;
- S:2、9、6、3;
- S:2、9、6、3;
- 读到了/
- 开始运算:Y/X 其中X=3,Y=6,得到2
- 此时S:2、9、2;
- 读到了+
- 开始运算:Y+X 其中X=2,Y=9,得到11
- 此时S:2、11;
- S:2、11、5;
- 读到了-
- 开始运算:Y-X 其中X=5,Y=11,得到6
- 此时S:2、6;
- 读到了*
- 开始运算:Y*X 其中X=6,Y=2,得到12
- 此时S:12;
- S:12、4;
- 读到了+
- 开始运算:Y+X 其中X=4,Y=12,得到16
- 此时S:16;
- 到达栈底,输出16
实例
用栈实现中缀表达式转化为后缀表达式,并用后缀表达式求值(Java)
Project A:用顺序表栈实现
Project B:用链栈实现
Project A:用顺序表栈实现
3大块:
- Stack类
- 中缀表达式变为后缀表达式 InToPost
- 利用栈对后缀表达式求值PostToOut
Stack类
package A;
public class Stack {
private int maxSize;
private char[] stackArray;
private int top;
public Stack(int max) {
maxSize = max;
stackArray = new char[maxSize];
top = -1;
}
public void push(char j) {
stackArray[++top] = j;
}
public char pop() {
return stackArray[top--];
}
public boolean isEmpty() {
return (top == -1);
}
}
用栈实现中缀表达式转化为后缀表达式
- 遇到运算数,直接输出
- 遇到左括号, 压入栈
- 遇到右括号,说明括号里的中缀表达式已经扫描完毕,将栈顶的运算符弹出并输出,直到遇见左括号(左括号出栈,但是不输出)
- 遇到运算符A,如果A的优先级大于栈顶的运算符B的优先级,则把A压栈;如果优先级A<B,将B输出,再比较新的栈顶的运算符C,同样的道理,直到A的优先级大于栈顶运算符的优先级为止,然后将A压栈
- 中缀表达式元素处理完完毕时,把栈中留存的运算符一并输出
实现:
package A;
public class InToPost {
public static void main(String[] args) {
String input = "2*(9+6/3-5)+4";
String output;
InToPost theTrans = new InToPost(input);
output = theTrans.doTrans();
System.out.println("Postfix is " + output + '\n');
}
private Stack theStack;
private String input;
private String output = "";
public InToPost(String in) {
input = in;
int stackSize = input.length();
theStack = new Stack(stackSize);
}
public String doTrans() {
for (int j = 0; j < input.length(); j++) {
char ch = input.charAt(j);
switch (ch) {
// 遇到运算符A,如果A的优先级大于栈顶的运算符B的优先级,则把A压栈;
// 如果优先级A<B,将B输出,再比较新的栈顶的运算符C,
// 同样的道理,直到A的优先级大于栈顶运算符的优先级为止,然后将A压栈
case '+':
case '-':
gotOper(ch, 1);
break;
case '*':
case '/':
gotOper(ch, 2);
break;
// 遇到左括号, 压入栈
case '(':
theStack.push(ch);
break;
// 到右括号,说明括号里的中缀表达式已经扫描完毕,将栈顶的运算符弹出并输出,直到遇见左括号(左括号出栈,但是不输出)
case ')':
gotParen(ch);
break;
// 遇到运算数,直接输出
default:
output = output + ch;
break;
}
}
// 中缀表达式元素处理完完毕时,把栈中留存的运算符一并输出
while (!theStack.isEmpty()) {
output = output + theStack.pop();
}
System.out.println(output);
return output;
}
// 遇到运算符A,如果A的优先级大于栈顶的运算符B的优先级,则把A压栈;
// 如果优先级A<B,将B输出,再比较新的栈顶的运算符C,
// 同样的道理,直到A的优先级大于栈顶运算符的优先级为止,然后将A压栈
public void gotOper(char opThis, int prec1) {
while (!theStack.isEmpty()) {
char opTop = theStack.pop();
if (opTop == '(') {
theStack.push(opTop);
break;
}
else {
int prec2;
if (opTop == '+' || opTop == '-')
prec2 = 1;
else
prec2 = 2;
if (prec2 < prec1) {
theStack.push(opTop);
break;
}
else
output = output + opTop;
}
}
theStack.push(opThis);
}
// 中缀表达式元素处理完完毕时,把栈中留存的运算符一并输出
public void gotParen(char ch){
while (!theStack.isEmpty()) {
char chx = theStack.pop();
// 剔除左括号
if (chx == '(')
break;
else
output = output + chx;
}
}
}
控制台输出:
接下来用后缀表达式求值:
A方案:首先把2963/+5-*4+这个字符串,倒序变成新的栈A(栈低)+4*-5+/3692(栈顶)。栈A作为表达式,栈S来作为中转栈
B方案:也可以把2963/+5-*4+直接操作这个字符串A,栈S来作为中转栈
正常计算机肯定是吧上面控制台的输出放在一个栈里,所以要用A方案,但是前面就不改了,我们使用B方案
哎呀。。。突然发现,这好像只能是9以内的加减乘除啊,如果是大于10的话,那栈的底层就不应该是字符数组了,算了先跑起来
哎呀。。。还是不行,因为中间要压的某个数字已经有两位的了,算了,前面的不改,我们新建一个底层是int数组的栈IntStack,先跑起来
package A;
public class IntStack {
private int maxSize;
private int[] stackArray;
private int top;
public IntStack(int max) {
maxSize = max;
stackArray = new int[maxSize];
top = -1;
}
public void push(int j) {
stackArray[++top] = j;
}
public int pop() {
return stackArray[top--];
}
public boolean isEmpty() {
return (top == -1);
}
}
- 建立一个栈S ,左到右读后缀表达式,
- 读到数字就将它转换为数值压入栈S中,
- 读到运算符则从栈中依次弹出两个数分别到X和Y,
- 然后以“Y 运算符 X”的形式计算机出结果,
- 再压加栈S中 ,果后缀表达式未读完,就重复上面过程,最后输出栈顶的数值则为结束。
package A;
public class PostToOut {
public static void main(String[] args) {
String post = "2963/+5-*4+";
int output;
PostToOut postToOut = new PostToOut(post);
output = postToOut.doCalculate();
System.out.println("Value is " + output + '\n');
}
private String post;
private IntStack theStack;
private int output=0;
public PostToOut(String po){
post=po;
int stackSize=po.length();
theStack=new IntStack(stackSize);
}
public int doCalculate(){
for (int i = 0; i <post.length() ; i++) {
int x=0;
int y=0;
char ch=post.charAt(i);
switch(ch){
case '+':
{
x= theStack.pop();
y= theStack.pop();
output=y+x;
theStack.push(output);
break;
}
case '-':
{
x= theStack.pop();
y= theStack.pop();
output=y-x;
theStack.push(output);
break;
}
case '*':
{
x= theStack.pop();
y= theStack.pop();
output=y*x;
theStack.push(output);
break;
}
case '/':
{
x= theStack.pop();
y= theStack.pop();
output=y/x;
theStack.push(output);
break;
}
default: {
theStack.push((int)(ch-'0'));
break;
}
}
}
return output;
}
}
Project B:用链栈实现
待更新