数据结构和算法之栈

中缀表达式使用栈实现计算器

package stack;

//中缀表达式使用栈实现计算器
import java.util.Scanner;

//定义一个ArrayStack2表示栈
class ArrayStack2{
    private int maxSize;//栈的大小
    private int[] stack;//栈的数据存在该数组中
    private int top=-1;//top表示栈顶,没有数据时为-1
    private int num1;
    private int num2;
    private int oper;

    //构造器
    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("栈空");
            //return;//不需要return,抛出异常本身就带有终止程序
        }
        int value=stack[top];
        top--;
        return value;
    }

    //显示栈的情况
    public void disPlay(){
        //遍历时需要从栈顶开始显示数据
        if (isEmpty()){
            System.out.println("栈空,没有数据");
            return;
        }
        for (int i = top; i>=0 ; i--) {//从栈顶开始遍历
            System.out.println("第"+i+"个数据为"+stack[top]+" ");
        }

    }
    //返回运算符的优先级,优先级使用数字表示,数字越大优先级越高,假定表达式中只含有+-*/
    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){
        this.num1 = num1;
        this.num2 = num2;
        this.oper = oper;
        int res=0;//用于存放计算结果
        switch(oper){
            case '+':
                res=num1+num2;
                break;
            case '-':
                res=num2-num1;
                break;
            case '*':
                res=num1*num2;
                break;
            case '/':
                res=num2/num1;
                break;
                default:
                    break;
        }
        return res;
    }
}
public class Calculator {
    public static void main(String[] args) {
        //根据思路完成表达式的计算
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入计算表达式:");
        String expression=sc.next();
        //创建两个栈,数栈和符号栈
        ArrayStack2 numStack=new ArrayStack2(10);
        ArrayStack2 operStack=new ArrayStack2(10);

        //定义相关变量
        int index=0;//用于扫描
        int num1=0;
        int num2=0;
        int oper=0;
        int res=0;
        char ch=' ';//将每次扫描得到的char保存在ch中

        //定义一个字符串变量用于拼接多位数
        String keepNum="";

        //开始用while循环扫描expression
        while (true){
            //依次得到expression的每一个字符
            ch=expression.subSequence(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{//如果是数字,直接入数栈
                //numStack.Push(ch-48);//从字符转换为数字
                //分析多位数入栈情况
                //1.当处理多位数时,不能发现是数字就入栈,因为可能是多位数
                //2.在处理数时,需要向表达式的index再往后看一位来判断它是不是多位数,如果是就继续扫描,否则入栈
                //3.需要定义一个字符串变量用于拼接

                //处理多位数
                keepNum+=ch;
                //如果ch已经是表达式的最后一位就直接入栈
                if (index==expression.length()-1){
                    numStack.Push(Integer.parseInt(keepNum));
                }else{
                //判断下一个字符是不是数字,是数字继续扫描,如果是运算符就入数栈
                //只是向后再看一位不是index++
                if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))){
                    //如果条件满足那么后一位就是运算符,那么就入数栈,keep="1","123"
                    numStack.Push(Integer.parseInt(keepNum));//要将keepNum转化为数字入数栈,此方法就可以
                    //入数栈后记得将keepNum清空,不然下一次会在原来基础上拼接
                    keepNum="";
                }
                }
            }
            //让index++,并判断是否扫描到最后
            index++;
            if (index>=expression.length()){
                break;
            }
        }
        //做扫描完毕后的处理
        while (true){
            //如果符号栈为空计算结束,数占中只有一个数值就是结果
            if (operStack.isEmpty()){
                break;
            }
            num1=numStack.Pop();
            num2=numStack.Pop();
            oper=operStack.Pop();
            res=numStack.cal(num1,num2,oper);
            numStack.Push(res);//入栈
        }
        int res2=numStack.Pop();
        System.out.println("结果为:");
        System.out.println(res2);
    }
}

中缀表达式转后缀表达式计算器
在这里插入图片描述在这里插入图片描述

package stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolandNotation {
    public static void main(String[] args) {
        //中缀表达式转后缀表达式:1+((2+3)*4)-5——》1 2 3 + 4 * + 5 -
        //1.将中缀表达式转化成中缀表达式对应的list
        //2.将中缀表达式对应的list转化成后缀表达式对应的list
        // [1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]-》[1,2,3,+,4,*,+,5,-],消除括号
        String expression="1+((2+3)*4)-5";
        List<String> infixExpressionList=toInfixExpressionList(expression);
        System.out.println("中缀表达式对应的list="+infixExpressionList);
        List<String> suffixExpressionList = parseSuffixExpressionList(infixExpressionList);
        System.out.println("后缀表达式对应的list="+suffixExpressionList);
        System.out.println(expression+"="+calculate(suffixExpressionList));
        //先定义一个逆波兰表达式
        //(3+4)*5-6-->3 4+ 5 * 6 -
        //String suffixExpression="3 4 + 5 * 6 - ";//后缀表达式
        //思路:
        //1.先将表达式放在ArrayList当中,便于快速扫描
        //2.将ArrayList传递给一个方法,配合栈完成计算
        /*List<String> list=getListString(suffixExpression);
        System.out.println("rpnList: "+list);
        int res=calculate(list);
        System.out.println(res);*/
    }

    // [1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]-》[1,2,3,+,4,*,+,5,-],消除括号
    //方法:
    public static List<String> parseSuffixExpressionList(List<String> ls){
        //定义两个栈
        Stack<String> s1=new Stack<String>();//符号栈
        //因为s2这个栈,在整转换过程中,没有pop操作,我们后面要逆序输出后缀表达式
        //因此我们不用 Stack<String>,只接使用List<String> s2
        //Stack<String> s2=new Stack<String>();//存储中间结果栈
        List<String> s2=new ArrayList<String>();//用于存储中间结果的ArrayList s2
        //遍历ls
        for(String item:ls){
            //如果是一个数就入加入到s2
            if (item.matches("\\d+")){//使用正则表达式
                s2.add(item);
            }else if(item.equals("(")){
                s1.push(item);
            }else if (item.equals(")")){
                //如果是“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时这一对括号将丢弃
                while (!s1.peek().equals("(")){//peek()查看栈顶的内容,并不改变
                    s2.add(s1.pop());//把s1内容弹出加入到s2中,知道遇到)结束
                }
                s1.pop();//将(弹出s1栈,就是消除小括号
            }else{
                //考虑优先级,当item的优先级小于等于s1栈顶的运算符优先级
                // 将s1栈顶的运算符弹出并加入到s2中,再次转到4.1与s1中新的栈顶运算符相比较
                //缺少比较优先级高低的方法
                while (s1.size()!=0&&
                        Operation.getValue(s1.peek()) >=Operation.getValue(item)){
                    s2.add(s1.pop());
                }
                //还需要将item压入s2栈中
                s1.push(item);
            }
        }
        //将s1中剩余的运算符依次弹出并加入到s2中
        while (s1.size()!=0){
            s2.add(s1.pop());
        }
        return s2;//因为是存放到list中,因此按顺序输出就是后缀表达式对应的list
    }

    //将中缀表达式转成对应的list
    public static List<String> toInfixExpressionList(String s){
        //定义一个List存放中缀表达式对应的内容
        List<String> ls=new ArrayList<String>();
        int i=0;//用于扫描中缀表达式字符串
        String str;//用于对多位数进行拼接
        char c;//每遍历一个字符,就放入到c
        do {
            //如果c是非数字,那么加到ls中
            if ((c=s.charAt(i))<48||(c=s.charAt(i))>57){
                ls.add(""+c);
                i++;//需要后移
            }else{//如果是数字,需要考虑多位数的问题
                str="";//先将str置成空串
                while (i<s.length()&&(c=s.charAt(i))>=48&&(c=s.charAt(i))<=57){
                    str+=c;//拼接
                    i++;
                }
                ls.add(str);
            }
        }while (i<s.length());
        return ls;
    }

    //将逆波兰表达式,将数据和运算符放入到ArrayList中
   /* public static List<String> getListString(String suffixExpression){
        //将suffixExpression分割
        String[] split=suffixExpression.split(" ");
        List<String> list=new ArrayList<String>();
        for(String ele:split ){
            list.add(ele);
        }
        return list;
    }*/
    //完成对逆波兰表达式的计算
    /*
    * 1.从左向右扫描,将3和4压入堆栈
    * 2.遇到+运算符,弹出4和3(4是栈顶元素,3是次栈顶元素),计算3+4,将结果7入栈
    * 3.将5入栈
    * 4.接下来扫描到*运算符,弹出5和7,计算5*7,将结果34入栈
    * 5.将6入栈
    * 6.扫描到-运算符弹出6和35,计算35-6,将结果29入栈,得到最终结果
    * */

    public static int calculate(List<String> ls){
        //创建一个栈即可
        Stack<String> stack=new Stack<String>();
        //遍历ls
        for (String item:ls){
            //使用正则表达式取出数
            if (item.matches("\\d+")){//匹配的是多位数
                //入栈
                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("运算符有误");
                }
                //将res入栈
                stack.push(""+res);
            }
        }
        //最后留在Stack中的数据就是运算结果
        return Integer.parseInt(stack.pop());
    }
}
//编一个比较运算符优先级的类
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:
                    System.out.println("不存在该运算符!");
                    break;
        }
        return result;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值