栈是什么

概念

栈Stack:栈顶插入或者删除,栈底不变

基本操作:入栈push,出栈pop

按照存储方式分类

  1. 顺序存储:顺序栈
  2. 链式存储:链栈

 

 

中缀表达式和后缀表达式

定义:

比如: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);
    }
}

用栈实现中缀表达式转化为后缀表达式

  1. 遇到运算数,直接输出
  2. 遇到左括号, 压入栈
  3. 遇到右括号,说明括号里的中缀表达式已经扫描完毕,将栈顶的运算符弹出并输出,直到遇见左括号(左括号出栈,但是不输出)
  4. 遇到运算符A,如果A的优先级大于栈顶的运算符B的优先级,则把A压栈;如果优先级A<B,将B输出,再比较新的栈顶的运算符C,同样的道理,直到A的优先级大于栈顶运算符的优先级为止,然后将A压栈
  5. 中缀表达式元素处理完完毕时,把栈中留存的运算符一并输出

实现:

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);
    }
}
  1. 建立一个栈S ,左到右读后缀表达式,
  2. 读到数字就将它转换为数值压入栈S中,
  3. 读到运算符则从栈中依次弹出两个数分别到X和Y,
  4. 然后以“Y  运算符   X”的形式计算机出结果,
  5. 再压加栈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:用链栈实现

待更新

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值