栈与逆波兰表达式

1.背景

栈经常被面试到

'6+8-(4X5)-2'如何解析并运算

逆波兰表达式

2.使用栈实现简单的计算表达式

复制代码
package com.ldp.structure.demo01;

import org.junit.Test;

import java.util.Scanner;

/**
 * 基于数组的栈
 */
public class Test04ArrayStack {
    /**
     * 基于数组的栈演示
     *
     * @param args
     */
    public static void main(String[] args) {
        ArrayStack arrayStack = new ArrayStack(3);
        Scanner scanner = new Scanner(System.in);
        String key = "";
        boolean flag = true;
        while (flag) {
            System.out.println("(s)show查看队列");
            System.out.println("(p)push添加一个元素");
            System.out.println("(o)pop获取一个元素");
            System.out.println("(e)exit退出系统");
            key = scanner.next();
            switch (key) {
                case "s":
                    arrayStack.show();
                    break;
                case "p":
                    System.out.println("请输入一个数字:");
                    arrayStack.push(Integer.valueOf(scanner.next()));
                    break;
                case "o":
                    try {
                        System.out.println(arrayStack.pop());
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case "e":
                    System.out.println("退出系统");
                    flag = false;
                    break;
                default:
                    System.out.println("输入错误");
            }
        }
    }

    /**
     * 基于栈实现解析运算表达式如:  3+9/3 = 6
     */
    @Test
    public void test01() {
        // String expression = "3+2*5-1"; // 12
        // String expression = "3+9/3"; // 6
        // String expression = "3+9/3-2+8/2-1"; // 7   3+3-2+4-1=7
        String expression = "3+2*6-2"; // 13
        // 定义数栈
        ArrayStack numStack = new ArrayStack(10);
        // 定义符号栈
        ArrayStack operationStack = new ArrayStack(10);
        // 下标
        int index = 0;
        // 这次计算乘法和除法
        while (index < expression.length()) {
            String str = expression.substring(index, index + 1);
            // 入栈
            if (OperationUtil.isOperation(str)) {
                // 检查优先级,如果是乘或者除就执行运算
                if (OperationUtil.priorityNum(str) == 1) {
                    // 取出下一个数字
                    index++;
                    String str2Num = expression.substring(index, index + 1);
                    // 取出数字栈中的第一个数字
                    String str1Num = (String) numStack.pop();
                    // 执行运算
                    int calculation = OperationUtil.calculation(Integer.valueOf(str1Num), str, Integer.valueOf(str2Num));
                    // 将计算的结果放入数字栈中,以字符串的形式放入
                    numStack.push(String.valueOf(calculation));
                } else {
                    // 加法 减法先放入栈中
                    operationStack.push(str);
                }
            } else {
                numStack.push(str);
            }
            // 向下移动一个角标
            index++;
        }
        // 计算加法 和 减法
        // 倒序
        numStack = numStack.resv(numStack);
        operationStack = operationStack.resv(operationStack);
        while (!operationStack.isEmpty()) {
            String num1 = (String) numStack.pop();
            String num2 = (String) numStack.pop();
            String operation = (String) operationStack.pop();
            // 应从栈里面取出来的是最新的数据,因此应交换计算
            int calculation = OperationUtil.calculation(Integer.valueOf(num1), operation, Integer.valueOf(num2));
            // 将计算结果放入数字栈中
            numStack.push(String.valueOf(calculation));
        }
        System.out.println("测试完成....结果:" + numStack.pop());
    }
}

class ArrayStack {
    Object[] data;
    int top = -1;
    int size;

    public ArrayStack(int size) {
        this.size = size;
        this.data = new Object[size];
    }

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

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

    // 入栈
    public void push(Object i) {
        if (isFull()) {
            System.out.println("栈栈满.....");
        } else {
            top++;
            data[top] = i;
        }
    }

    // 出栈
    public Object pop() {
        if (isEmpty()) {
            throw new RuntimeException("栈中无数据...");
        }
        Object n = data[top];
        top--;
        return n;
    }

    // 栈倒序
    public ArrayStack resv(ArrayStack stack) {
        ArrayStack arrayStackNew = new ArrayStack(stack.size);
        while (!stack.isEmpty()) {
            arrayStackNew.push(stack.pop());
        }
        return arrayStackNew;
    }


    // 显示栈的情况(遍历)
    public void show() {
        if (isEmpty()) {
            System.out.println("栈中无数据....");
            return;
        }
        for (int i = top; i >= 0; i--) {
            System.out.print(data[i] + " \t");
        }
        System.out.println();
    }

}

class OperationUtil {
    // 判定是否为符号
    public static boolean isOperation(String str) {
        if (str == null) {
            return false;
        }
        if (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")) {
            return true;
        }
        return false;
    }

    // 判定优先级,值越大越优先, + - 为0, * / 为1
    public static int priorityNum(String str) {
        if (str.equals("+") || str.equals("-")) {
            return 0;
        } else if (str.equals("*") || str.equals("/")) {
            return 1;
        } else {
            return -1;
        }
    }

    /**
     * 计算
     *
     * @param num1      第一个运算数字
     * @param operation 运算符
     * @param num2      第二个运算数字
     * @return
     */
    public static int calculation(int num1, String operation, int num2) {
        int result = 0;
        if ("+".equals(operation)) {
            result = num1 + num2;
        } else if ("-".equals(operation)) {
            result = num1 - num2;
        } else if ("*".equals(operation)) {
            result = num1 * num2;
        } else if ("/".equals(operation)) {
            result = num1 / num2;
        } else {
            throw new RuntimeException("运算符未知:" + operation);
        }
        return result;
    }
}
View Code
复制代码

 

3.使用逆波兰表达式实现带有括号的表达式

3.1.中缀表达式转逆波兰表达式思路

3.2.逆波兰表达式计算

复制代码
package com.ldp.structure.demo01;

import org.junit.Test;

import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

/**
 * 后缀表达式(逆波兰表达式)
 */
public class Test06Suffix {
    /**
     * 中缀表达式转后缀表达式
     */
    @Test
    public void testInfillToSuffix() {
        String expression = "6+8-(4*5)-2";//
        System.out.println("中缀表达式:" + expression);
        List<String> list = infillToSuffix(expression);
        System.out.println("后缀表达式:" + list);
        int count = suffixCount(list);
        System.out.println("后缀表达式计算出来的结果: " + expression + "=" + count);
    }

    /**
     * 后缀表达式执行运算
     */
    @Test
    public void testSuffixCount() {
        String expression = "6+8-(4*5)-2";
        List<String> list = infillToSuffix(expression);
        System.out.println(list);
    }

    /**
     * 是数字就直接入栈,是符号就弹出2个数进行运算,最后栈你只会剩下一个数,就是结果
     *
     * @param list
     * @return
     */
    public int suffixCount(List<String> list) {
        Stack<String> stack = new Stack<>();
        for (String str : list) {
            if (isOperation(str)) {
                String number2 = stack.pop();
                String number1 = stack.pop();
                int calculation = calculation(Integer.valueOf(number1), str, Integer.valueOf(number2));
                stack.push("" + calculation);
            } else {
                stack.push(str);
            }
        }
        return Integer.valueOf(stack.pop());
    }

    /**
     * 中缀表达式转为后缀表达式,使用ArrayList存放
     */
    public List<String> infillToSuffix(String expression) {
        // 定义一个存放符号的临时栈stack1
        Stack<String> stack1 = new Stack<>();
        // 定义一个存放数字和符号的栈stack2
        Stack<String> stack2 = new Stack<>();
        // 接收字符的临时变量
        String strTemp = "";
        int index = 0;
        while (index < expression.length()) {
            String str = expression.substring(index, index + 1);
            if ("(".equals(str)) { // 直接入栈
                stack1.push(str);
                index++;
            } else if (")".equals(str)) {
                // 将stack1中的符号弹出到stack2直到 stack1中弹出"("为止,即丢弃一对括号
                while (true) {
                    String item = stack1.pop();
                    if ("(".equals(item)) {
                        index++;
                        break;
                    }
                    stack2.push(item);
                }
            } else if (isOperation(str)) {
                // 运算符号
                while (true) {
                    // 如果stack1栈顶为空 或者不是 运算符 直接入栈
                    if (stack1.isEmpty() || !isOperation(stack1.peek())) {
                        stack1.push(str);
                        index++;
                        break;
                    } else if (priorityNum(str) > priorityNum(stack1.peek())) {
                        // 比栈顶优先级高直接入栈
                        stack1.push(str);
                        index++;
                        break;
                    } else {
                        // 将stack1栈顶运算符弹出到stack2
                        stack2.push(stack1.pop());
                    }
                }
            } else {
                // 数字
                stack2.push(str);
                index++;
            }
        }
        // 将stack1中的运算符弹出到stack2
        while (!stack1.isEmpty()) {
            stack2.push(stack1.pop());
        }
        // 倒序放入list中
        LinkedList<String> list = new LinkedList();
        while (!stack2.isEmpty()) {
            list.addFirst(stack2.pop());
        }
        return list;
    }

    // 当前运算符低于栈顶运算符时,将栈顶运算符弹出到stack2
    public void handleOperation() {
    }

    // 判定是否为符号
    public static boolean isOperation(String str) {
        if (str == null) {
            return false;
        }
        if (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")) {
            return true;
        }
        return false;
    }

    // 判定优先级,值越大越优先, + - 为0, * / 为1
    public static int priorityNum(String str) {
        if (str.equals("+") || str.equals("-")) {
            return 0;
        } else if (str.equals("*") || str.equals("/")) {
            return 1;
        } else {
            return -1;
        }
    }

    /**
     * 计算
     *
     * @param num1      第一个运算数字
     * @param operation 运算符
     * @param num2      第二个运算数字
     * @return
     */
    public static int calculation(int num1, String operation, int num2) {
        int result = 0;
        if ("+".equals(operation)) {
            result = num1 + num2;
        } else if ("-".equals(operation)) {
            result = num1 - num2;
        } else if ("*".equals(operation)) {
            result = num1 * num2;
        } else if ("/".equals(operation)) {
            result = num1 / num2;
        } else {
            throw new RuntimeException("运算符未知:" + operation);
        }
        return result;
    }
}
复制代码

 

完美!

posted @   不停学  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示