栈的实例应用

     我们把平时所用的标准四则运算表达式,即“9+(3-1)×3+10÷2”叫做中缀表达式。下面我们用栈来实现综合计算器。

     使用栈完成表达式的计算思路

  1.   通过一个index值来遍历表达式
  2. 如果发现是数字直接入栈
  3. 如果发现当前符号栈为空,就直接入栈
  4. 如果符号栈不为空,就要进行比较。如果当前操作符优先级<=栈中的操作符,就需要从数栈中pop俩个数,符号栈pop一个进行运算,得到的结果入数栈,当前读取到的操作符入符号栈,如果当前优先级大的话,直接入符号栈
  5. 当前表达式扫描完毕,就顺序从数栈和符号栈中pop出相应的数和符号,并运行
  6. 数栈最后一个数字就是表达式结果

代码实现:

package com.jxust.stack;

public class ComouterStack {
    public static void main(String[] args) {
        //根据前面老师思路,完成表达式的运算
        String expression="7-6-1-8";
        //创建两个栈,数栈,一个符号栈
        ArrayStack2 numStack=new ArrayStack2(10);
        ArrayStack2 operStack=new ArrayStack2(10);
        //定义需要的相关变量
        int index=0;//用于扫描
        int num1=0;
        int num2=0;
        int res=0;
        int oper=0;
        char ch=' ';//将每次扫描得到char保存到ch
        String keepNum="";
        while (true){
            //依次得到expression的每一个字符
            ch=expression.substring(index,index+1).charAt(0);
            //判断ch是什么,如何做相应的处理
            if(operStack.isOper(ch)){//如果是运算符

                //判断当前的符号栈是否为空
                if(!operStack.isEmpty()){
                    //如果当前的操作符的优先级小于或等于栈中的操作符
                    if(operStack.priority(ch)<=operStack.priority(operStack.peek())){
                        num1=numStack.pop();
                        num2=numStack.pop();
                        oper=operStack.pop();
                        res=numStack.cal(num1,num2,oper);

                        //把运算的结果放入数栈
                        numStack.push(res);
                        //然后将当前的操作符入符号栈
                        operStack.push(ch);
                    }else{
                        //如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈
                        operStack.push(ch);
                    }
                }
                else {
                    //如果为空,直接入栈
                    operStack.push(ch);
                }
            }
            else{
                //1.当处理多位数时,不能发现是一个数就立刻入栈,因为他可能是多位数
                //2.在处理数,需要向expression的表达式的index后再看以为,如果是数就进行扫描,如果是符号才入栈
                //3.因此我们需要定义一个变量字符串,用于拼接

                //处理多位数
                keepNum+=ch;

                //判断下一个字符是不是数字,如果是数字,就继续扫描,如果是运算符,则入栈
                //注意是看后一位,不是index++
                if(index==expression.length()-1){
                    numStack.push(Integer.parseInt(keepNum));
                }
                else {
                    if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) {
                        //如果后一位是运算符,则入栈
                        numStack.push(Integer.parseInt(keepNum));
                        keepNum = "";
                    }
                }
            }
            //让index+1,并判断是否扫描到expression最后
            index++;
            if(index>=expression.length()){
                break;
            }
        }

        //当表达式扫描完毕,就顺序的从数栈和符号栈中pop出相应的数和符号,并运行。
        while(true){
            //如果符号栈为空,则计算到最后的结果,数栈中只有一个数字【结果】
            if(operStack.isEmpty()){
                break;
            }
            num1=numStack.pop();
            num2=numStack.pop();
            oper=operStack.pop();
            res=numStack.cal(num1,num2,oper);
            numStack.push(res);//入栈
        }


        //将数栈的最后数,pop出,就是结果
        int res2=numStack.pop();
        System.out.printf("表达式%s=%d",expression,res2);

    }



    static class ArrayStack2 {
        private int maxSize;//栈的大小
        private int[] stack;//数组、数组模拟栈
        private int top = -1;//top表示栈顶,初始化为-1

        //构造器
        public ArrayStack2(int maxSize) {
            this.maxSize = maxSize;

            stack = new int[this.maxSize];
        }

        //返回当前栈顶的值 不是真正的出栈
        public int peek() {
            return stack[top];
        }

        //栈满
        public boolean isFull() {
            return top == maxSize - 1;
        }

        //栈空
        public boolean isEmpty() {
            return top == -1;
        }

        //入栈
        public void push(int value) {
            if (isFull()) {
                System.out.println("栈满");
                return;
            }

            top++;
            stack[top] = value;
        }

        public int pop() {
            if (isEmpty()) {
                throw new RuntimeException("栈空");
            }

            int value = stack[top];
            top--;
            return value;
        }

        public void list() {
            if (isEmpty()) {
                System.out.println("栈空");
                return;
            }

            for (int i = top; i >= 0; i--) {
                System.out.printf("stack[%d]=%d\n", i, stack[i]);
            }

        }

        //判断运算符的优先级
        public int priority(int oper) {
            if (oper == '*' || oper == '/') return 1;
            else if (oper == '+' || oper == '-') return 0;
            else return -1;

        }

        //判断是不是运算符
        public boolean isOper(char val) {
            return val == '+' || val == '-' || val == '*' || val == '/';
        }

        //计算方法
        public int cal(int num1, int num2, int oper) {
            int res = 0;

            switch (oper) {
                case '+':
                    res = num2 + num1;
                    break;
                case '-':
                    res = num2 - num1;
                    break;
                case '*':
                    res = num2 * num1;
                    break;
                case '/':
                    res = num2 / num1;
                    break;
                default:
                    break;
            }

            return res;
        }

    }


}

后缀表达式一种不需要括号的后缀表达法我们先来看看,对于“9+(3-1)×3+10÷2”,如果要用后缀表示法应该是什么样子:“9 3 1 - 3 * + 10 2 / +”,这样的表达式称为后缀表达式,叫后缀的原因在于所有的符号都是在要 运算数字的后面出现。

规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就
将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果

 

 

 

 

 

 

Java代码实现

package com.jxust.stack;

import javax.swing.plaf.nimbus.State;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Stack;

public class PolandNotation {

    public static void main(String[] args) {

      String expression="1+((2+3)*4)-5";
        List<String> list1=toex(expression);
        System.out.println(list1);

        List<String> parlist=pslist(list1);

        System.out.println("后缀表达式对应的list"+ parlist);

        System.out.println("结果是:"+calculate(parlist));
//        // 逆波兰表达式 (3+4)*5-6 =>>  3 4 + 5 * 6 -
//
//        String suffixExpression = "34 4 + 5 * 6 -";
//        List<String> relist = getList(suffixExpression);
//        System.out.println("list=" + relist);
//        int res = calculate(relist);
//        System.out.println("计算结果是:" + res);


    }


    public static List<String> pslist(List<String> ls) {

        Stack<String> s1 = new Stack<String>();
        List<String> s2 = new ArrayList<String>();

        for (String item :
                ls) {
            if (item.matches("\\d+")) {
                s2.add(item);
            } else if (item.equals("(")) {
                s1.push(item);
            } else if (item.equals(")")) {
                while (!s1.peek().equals("(")) {
                    s2.add(s1.pop());
                }
                s1.pop();//将(弹出 ,消除一对小括号
            } else {
                //当item的优先级小于等于栈顶运算符优先级的话,
                //栈顶的运算符弹出并加入s2中,再次与s1中新栈顶运算符相比较
                while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {
                    s2.add(s1.pop());
                }

                s1.push(item);

            }
        }

        while (s1.size()!=0) s2.add(s1.pop());

        return s2;

    }


    //将中缀表达式转为对应的list
    public static List<String> toex(String s){
        List<String> ls=new ArrayList<String>();
        int i=0;//指针用于遍历中缀表达式字符串
        String  str;
        char c;
        do{
            if ((c=s.charAt(i)) < '0' || (c=s.charAt(i)) > '9')
            { ls.add(""+c);  i++;}
            else{//如果是一个数,需要参考多位数
                str="";
                while ( i <s.length() && (c=s.charAt(i)) >= '0' && (c=s.charAt(i)) <= '9'){
                    str+=c; i++;
                }
                ls.add(str);
            }
        }
        while (i < s.length());

        return  ls;
    }


    //将一个逆波兰表达式,依次将数据和运算符放到ArrayList中
    public static List<String> getList(String s) {
        String[] split = s.split(" ");
        List<String> list = new ArrayList<String>();

        for (String ss : split
        ) {
            list.add(ss);
        }

        return list;
    }

    //完成对逆波兰表达式的运算


    public static int calculate(List<String> ls) {
        //创建栈
        Stack<String> stack = new Stack<String>();
        for (String item : ls) {//正则表达式取出数
            if (item.matches("\\d+")) {// 匹配多位数  \下一个数为特殊数   \d代表0-9
                stack.push(item);
            } else {
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res = 0;

                if (item.equals("+")) {
                    res = num1 + num2;
                } else if (item.equals("-")) {
                    res = num1 - num2;
                } else if (item.equals("*")) {
                    res = num1 * num2;
                } else if (item.equals("/")) {
                    res = num1 / num2;
                } else {
                    throw new RuntimeException("运算符有误");
                }
                stack.push(String.valueOf(res));
            }
        }
        //最后结果输出
        return Integer.parseInt(stack.pop());
    }

}

// Operation 可以返回一个运算符对应的优先级
class  Operation{
    private static int ADD=1;
    private static int SUB=1;
    private static int MUL=2;
    private static int DIV=2;

    //返回对应的优先级数字

    public static int getValue(String operation){
        int result=0;
        switch (operation){
            case "+":
                result =ADD;break;
            case "-":
                result =SUB;break;
            case "*":
                result =MUL;break;
            case "/":
                result= DIV;break;
            default:
                result=0;break;

        }
       return result;
    }

}


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值