【数据结构】栈的实际应用

关于表达式的知识

  • 前缀表达式:运算符都位于操作符之前。
    计算机求值:从右到左扫描,遇到数字,压入堆栈,遇到运算符,弹出栈顶和次栈元素。
  • 中缀表达式:就是正常的人类计算,但是计算机并不方便。一般会转换为后缀表达式(逆波兰表达式)。
  • 后缀表达式:与前缀表达式相似,只是运算符位于操作数之后。
    计算机求值:从左到右扫描,遇到数字,压入堆栈,遇到运算符,弹出栈顶和次栈元素,进行运算,结果放回栈。

栈实现计算器

给出中缀表达式,自动计算结果。(不包括括号、小数计算)

  • 思路分析
    创建数栈、符号栈。
  1. 通过index(索引)遍历表达式。
  2. 如果发现是数字,入数栈
  3. 如果发现是符号 :
    3.1 符号栈为空:直接入栈
    3.2 符号栈有操作符:
    1. 如果当前操作符优先级小于等于栈中操作符,从数栈pop两个数,再从符号栈pop一个操作符。计算结果入数栈,当前操作符入符号栈。
    2. 如果当前操作符优先级大于栈中操作符,就直接入符号栈。
  4. 当表达式扫描完毕,就顺序的从数栈和符号栈pop出相应地数和符号。

代码实现

import java.util.Stack;
/**
 * @Author 不知名网友鑫
 * @Date 2022/3/10
 **/
public class Calculator {
    //判断是否为符号。
    public static boolean isOper(char ch) {
        return ch == '+' || ch == '-' || ch == '*' || ch == '/';
    }
    //判断运算符优先级。
    public static int priority(char ch) {
        //优先级高就用1表示。
        if (ch == '*' || ch == '/') {
            return 1;
        } else if (ch == '+' || ch == '-') {
            return 0;
        }
        return -1;
    }
    //弹出两个数字,一个符号进行计算。
    public static int math(int num1, int num2, int oper) {
        switch (oper) {
            case '+':
                return num1 + num2;
            case '-':
                return num2 - num1;
            case '*':
                return num1 * num2;
            case '/':
                return num2 / num1;
            default:
                break;

        }
        return -1;
    }

    public static void main(String[] args) {
        StringBuffer s = new StringBuffer();
        String expression = "10/2+1-2";
        // 1.定义相关变量。
        // 数栈、符号栈、索引、取出符号、取出两个数字···
        Stack<Integer> numStack = new Stack<>();
        Stack<Character> operStack = new Stack<>();
        int index = 0;  //辅助指针,用来遍历String字符串
        int oper = 0;
        int num1 = 0;
        int num2 = 0;
        char ch; //保存每次得到的符号/数字。
        while (true) {
            if (index >= expression.length()) {
                break;
            }
            //获取index所指的位置。
            //刚开始指向String中的第一个,并拆分为char类型。
            ch = expression.substring(index, index + 1).charAt(0);
            // 1.如果ch是符号
            if (isOper(ch)) {
                // 1.1如果符号栈为空或者当前运算符优先级大于栈中运算符优先级
                if (operStack.isEmpty() || priority(ch) > priority(operStack.peek())) {
                    operStack.push(ch);
                } else {
                    num1 = numStack.pop();
                    num2 = numStack.pop();
                    oper = operStack.pop();
                    //把计算结果加入到数栈。
                    numStack.push(math(num1, num2, oper));
                    //把符号放入到符号栈。
                    operStack.push(ch);

                }
                // 2.如果ch是数。
            } else {
                //用StringBuffer不会产生多个对象,减少内存的损耗。
                s.append(ch);
                //如果是最后一位,直接加入即可。
                if (index == expression.length() - 1) {
                    numStack.push(Integer.parseInt(s.toString()));
                    //如果该位的下一位是字符,就将当前s中保存的数字入栈。
                } else if (isOper(expression.substring(index + 1, index + 2).charAt(0))) {
                    numStack.push(Integer.parseInt(s.toString()));
                    s.delete(0, s.length());
                }
            }
            index++;
        }

        while (true) {
            if (operStack.isEmpty()) {
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            numStack.push(math(num1, num2, oper));
        }
        System.out.println(numStack.pop());
    }
}

栈实现计算器2

给出中缀表达式,转换为后缀表达式并计算结果。(包括括号计算)

  • 思路分析
  1. 将中缀表达式传入ArrayList。
  2. 将中缀表达式的ArrayList转换为后缀表达式的ArrayList。
  3. 计算后缀表达式的ArrayList,输出结果。

代码实现

import java.util.ArrayList;
import java.util.Stack;
public class PolandExpression {
    public static void main(String[] args) {
        String suffixexpression ="1+((2+3)*4)-5";
        //将中缀表达式转换为ArrayList数组。
        ArrayList<String> s=ToList(suffixexpression);
        //中缀ArrayList数组转后缀ArrayList。
        ArrayList<String> s1=TosuffixExpression(s);
        //通过后缀表达式计算结果。
        System.out.println(calculate(s1));
    }

    public static int priority(String ch){
        switch(ch){
            case"+":
                return 0;
            case"-":
                return 0;
            case"*":
                return 1;
            case"/":
                return 1;
            default:
                 break;
        }
        return -1;
    }
    //1. 将中缀表达式转换为对应的ArrayList。
    public static ArrayList<String> ToList(String s){
        //创建ArrayList存放中缀表达式。
        ArrayList<String> a=new ArrayList<>();
        int index=0;
        do {
            StringBuffer sb = new StringBuffer();
            //如果此时是运算符,直接加入到ArrayList
            if (s.charAt(index) < 48 || s.charAt(index) > 57) {
                a.add(s.charAt(index) + "");
                index++;
                //如果此时是数字。
            } else {
                //while循环可以处理多位数的问题
                while (index < s.length() && s.charAt(index) >= 48 && s.charAt(index) <= 57) {
                    sb.append(s.charAt(index));
                    index++;
                }
                //添加到ArrayList中。
                a.add(sb.toString());
                //删除sb的内容
                sb.delete(0, sb.length());
            }
        }while(index<s.length());
        return a;  //返回转换后的ArrayList
    }
    //2.将中缀表达式的ArrayList转换为后缀表达式的ArrayList。
    public static ArrayList<String> TosuffixExpression(ArrayList<String> ls){
        //创建两个栈,s1、s2.
        Stack<String> s1=new Stack<>();
        //由于
        ArrayList<String> s2=new ArrayList<>();
        //item表示中缀ArrayList中的每一项。
        for(String item :ls){
            //2.1 如果是一个数字,直接入s2.
            if(item.matches("\\d+")){
                s2.add(item);
             //2.2 如果是左括号,直接入s1.
            } else if(item.equals("(")) {
                s1.push(item);
                //2.3 如果是一个右括号,就弹出s1压入s2,直到遇到左括号。并清空括号。
            } else if(item.equals(")") ){
                while(!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                //弹出左括号。
                s1.pop();
                //2.4 如果当前运算符优先级小于等于s1中栈顶运算符优先级,
                // 那么一直弹出s1加入s2,直到当前运算符优先级不小于s1栈顶运算符优先级或弹空。
            }else {
                    while(s1.size()!=0 &&priority(item)<=priority(s1.peek())){
                        s2.add(s1.pop());
                    }
                        s1.push(item);
                }

        }
        //5. s1中剩余的全部放入s2中。
        while(s1.size()!=0){
            s2.add(s1.pop());
        }
        return s2;

    }
    //将后缀表达式转换到ArrayList中。(暂无用)
    public static ArrayList<String> change(String s){
        ArrayList<String> arrayList=new ArrayList<>();
        String [] split=s.split(" ");
        for(String s1:split){
            arrayList.add(s1);
        }
        return arrayList;
    }
    //3. 计算最终的结果(使用后缀表达式)。
    //从左到右扫描,遇到数字,压入堆栈,遇到运算符,弹出栈顶和次栈元素,进行运算,结果放回栈。
    public static int calculate(ArrayList<String> ls){
        Stack<String> stack = new Stack<>();
        for(String s:ls){
            //正则表达式,匹配的是数字。
            if(s.matches("\\d+")){
                //如果是数字,直接入栈即可。
                stack.push(s);
            }else {
                //如果是运算符,取出栈中元素,并且计算。
                int num1=Integer.parseInt(stack.pop());
                int num2=Integer.parseInt(stack.pop());
                int res=0;
                if(s.equals("+")){
                    res=num1+num2;
                }else if(s.equals("-")){
                    res=num2-num1;
                }else if(s.equals("*")){
                    res=num1*num2;
                }else if(s.equals("/")){
                    res=num2/num1;
                }else {
                    throw new RuntimeException("Error");
                }
                //将res转换为字符串。
                stack.push(""+ res);
            }
        }
        //返回最后再栈中的结果就是运算的结果。
       return Integer.parseInt(stack.pop());
    }
}

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sivan_Xin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值