七、使用栈实现综合计算器(中缀表达式)

使用栈实现综合计算器(中缀表达式)

1.栈的实际需求

请输入一个表达式,计算式:[722-5+1-5+3-3] ,计算出结果
计算机底层是如何运算得到结果的? 注意不是简单的把算式列出运算,因为我们看这个算式 7 * 2 * 2 - 5, 但是计算机怎么理解这个算式的(对计算机而言,它接收到的就是一个字符串),我们讨论的是这个问题。-> 栈

2.使用栈实现表达式计算的大致思路(详细思路见代码)

(1)创建一个临时变量index索引,来遍历表达式;并创建两个栈空间,一个数栈,一个符号栈。
(2)从前往后遍历字符串,如果是一个数字,就直接入数栈。
(3)如果发现是一个符号,就分为如下情况
(3.1)如果当时符号栈为空就直接入符号栈
(3.2)如果符号栈不为空,就比较当前要入栈的符号与当前栈顶符号做比较;如果要入栈的符号小于等于栈顶符号的优先级,就从数栈中pop出两个数,并且从符号栈中pop出当前栈顶符号,进行运算,并将运算结果重新压入数栈中,然后将当前想要入栈的符号加入符号栈。
(3.3)如果当前的操作符的优先级大于栈顶符号,就直接加入符号栈
(4)当表达式遍历完毕时,就顺序的从数栈和符号栈中pop出相应的数和符号,并运算,之后将结果压入栈中,如此往复,直到符号栈中没有符号为止。
(5)当在数栈中只有一个数字时,就是表达式的结果

3.代码实现

package cn.zzw.algorithm.Stack;

import java.util.Scanner;

public class ArrayStackDemo1 {
    public static void main(String[] args) {

        //测试表达式的计算结果是否正确
        //当然在这里要思考一下如何处理多位数的加减乘除问题
        String expression="1000+102*2-6+2*4";

        //创建两个栈,一个用来存储数字,一个用来存储符号
        ArrayStack1 numStack=new ArrayStack1(15);
        ArrayStack1 operStack = new ArrayStack1(15);

        //定义需要的相关变量
        int index=0;
        int num1=0;
        int num2=0;
        int operator;
        int result=0;
        //将每次扫描得到的char保存到ch中
        char ch=' ';
        //用于拼接多位数
        String keepNum="";

        //使用while循环遍历表达式
        while (true)
        {
            //一次得到expression的每一个字符
            ch=expression.substring(index,index+1).charAt(0);
            //判断ch是什么,然后做相应的处理
            if (operStack.isOper(ch))
            {
                //如果是运算符,此时判断当前符号栈是否为空
                if (!operStack.isEmpty())
                {
                    //如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符, 就需要从数栈中 pop 出两个数,
                    //在从符号栈中 pop 出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符 号栈
                    if (operStack.priority(ch)<=operStack.priority(operStack.peek()))
                    {
                        num1=numStack.pop();
                        num2=numStack.pop();
                        operator=operStack.pop();
                        result=numStack.caluator(num1,num2,operator);
                        //将运算完的结果重新压入栈中
                        numStack.push(result);
                        //然后将当前操作符如符号栈
                        operStack.push(ch);
                    }
                    else
                    {
                        //此时是想要入栈的符号比符号栈顶的符号优先级大,就直接入栈
                        operStack.push(ch);
                    }
                }
                else
                {
                    //如果符号栈为空,就直接将其压入栈中
                    operStack.push(ch);
                }
            }
            //如果是数字,直接入数栈
            else
            {
                //由于有时候是多位数,分析思路如下
                //1.当处理多位数时,不能发现一个数就直接入栈
                //2.在处理数字时,需要想expression表达式的index后再看一位,如果是数就进行扫描,如果是符号就入栈
                //3.需要定义一个字符串变量,用于拼接
                keepNum+=ch;
                if (index==expression.length()-1)
                {
                    numStack.push(Integer.parseInt(keepNum));
                }
                else
                {
                    //判断下一个数字是不是数字,如果是就继续扫描,如果是运算符,则入栈
                    //注意是看后一位,不是index++
                    if(operStack.isOper(expression.substring(index+1,index+2).charAt(0)))
                    {
                        numStack.push(Integer.parseInt(keepNum));
                        //重要的是要注意把keepNum清空
                        keepNum="";
                    }
                }
            }
            //让index++,并判断是否到expression的最后
            index++;
            if(index>=expression.length())
            {
                break;
            }
        }

        //当表达式扫描完毕时,则顺序的从数栈和符号栈中弹出相应的数字和符号,并运算,并将运算结果压入栈中
        while(true)
        {
            //如果字符栈中字符为空,说明已经计算到了最后一步
            if(operStack.isEmpty())
            {
                break;
            }
            num1=numStack.pop();
            num2=numStack.pop();
            operator=operStack.pop();
            result=numStack.caluator(num1,num2,operator);
            numStack.push(result);
        }
        //这时数栈最后一个元素便是最后的结果
        int result2=numStack.pop();
        System.out.printf("表达式%s=%d",expression,result2);
    }
}

class ArrayStack1
{
    private int maxSize;
    private int[] stack;//使用数组模拟栈
    private int top=-1;

    //确定当前符号的优先级,优先级用数字表示
    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 caluator(int num1,int num2,int oper)
    {
        int result=0;
        switch (oper)
        {
            case '+':
                result=num1+num2;
                break;
            case '-':
                result=num2-num1;
                break;
            case '*':
                result=num1*num2;
                break;
            case '/':
                result=num2/num1;
                break;
            default:
                break;
        }
        return result;
    }

    //增加一个方法,可以返回当前符号栈的栈顶的值,但不是真正的pop
    public int peek()
    {
        return stack[top];
    }

    //构造器
    public ArrayStack1(int maxSize)
    {
        this.maxSize=maxSize;
        stack=new int[this.maxSize];
    }

    //判断栈满
    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]);
        }
    }
}



4.测试结果

"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:D:\IntelliJ IDEA\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=21513:D:\IntelliJ IDEA\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\Users\1\IdeaProjects\algorithm\out\production\algorithm" cn.zzw.algorithm.Stack.ArrayStackDemo1
表达式1000+102*2-6+2*4=1206
Process finished with exit code 0

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值