Java数据结构—前缀中缀波兰表达式

Posted 之墨_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java数据结构—前缀中缀波兰表达式相关的知识,希望对你有一定的参考价值。

Java数据结构—前缀、中缀、波兰表达式

逆波兰计算器

完成一个逆波兰计算器,要求完成如下任务:

  1. 输入一个逆波兰表达式(后缀表达式),使用栈(Stack), 计算其结果
  2. 支持小括号和多位数整数,计算器进行简化,只支持对整数的计算
  3. 思路分析


(3+4)X5-6对应的后缀表达式就是3 4 + 5 * 6 -,针对后缀表达式求值步骤如下:

  1. 从左至右扫描,将3和4压入堆栈;
  2. 遇到+运算符,因此弹出4和3 (4 为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
  3. 将5入栈;
  4. 接下来是X运算符,因此弹出5和7,计算出7X5=35,将35入栈;
  5. 将6入栈;
  6. 最后是-运算符,计算出35-6的值,即29, 由此得出最终结果

代码实现

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
 * @author 周润发
 * @date 2021/9/24 21:11
 */
public class PolandNotation {
    public static void main(String[] args) {

//        String suffixExression = "4 5 * 8 - 6 + 8 2 / +";
        String suffixExression = "30 4 + 5 * 6 -";
        List<String > list = getListString(suffixExression);
        System.out.println("rnList = "+ list);
        int res = calulate(list);
        System.out.println("result =" + res);
    }
     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,再将7入栈;
	3)将5入栈;
	4)接下来是X运算符,因此弹出5和7,计算出7X5=35,将35入栈;
	5)将6入栈;
	6)最后是-运算符,计算出35-6的值,即29,由此得出最终结果.
	 */
public static int calulate (List<String> ls) {
    Stack<String> stack = new Stack<String>();
    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("运算符有误");
            }
            stack.push("" + res);
        }
    }
    return Integer.parseInt(stack.pop());
}
    }

中缀表达式转换为后缀表达式

后缀表达式适合计算式进行运算,但是却不太容易写出来,尤其是表达式很长的情况下,因此在开发中,我们需要将中缀表达式转成后缀表达式

具体步骤

1)初始化两个栈:运算符栈s1储存中间结果的栈s2;
2)从左至右扫描中缀表达式;
3)遇到操作数时,将其压s2;
4)遇到运算符时,比较其与s1栈顶运算符的优先级:

1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;

5)遇到括号时

  1. 如果是左括号“(”,则直接压入s1
  2. 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号 丢弃
  3. 重复步骤2至5,直到表达式的最右边
  4. s1中剩余的运算符依次弹出并压入s2
  5. 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
/ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  =ArrayList [1,2,3,+,4,*,+,5,]
        //方法:将得到的中缀表达式对应的List => 后缀表达式对应的List
        public static List<String> parseSuffixExpreesionList(List<String> ls) {
            //定义两个栈
            Stack<String> s1 = new Stack<String>(); // 符号栈
            //说明:因为s2 这个栈,在整个转换过程中,没有pop操作,而且后面我们还需要逆序输出
            //因此比较麻烦,这里我们就不用 Stack<String> 直接使用 List<String> s2
            //Stack<String> s2 = new Stack<String>(); // 储存中间结果的栈s2
            List<String> s2 = new ArrayList<String>(); // 储存中间结果的Lists2

            //遍历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("(")) {
                        s2.add(s1.pop());
                    }
                    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压入栈
                    s1.push(item);
                }
            }

            //将s1中剩余的运算符依次弹出并加入s2
            while(s1.size() != 0) {
                s2.add(s1.pop());
            }
            return s2; //注意因为是存放到List, 因此按顺序输出就是对应的后缀表达式对应的List
        }

//方法:将 中缀表达式转成对应的List

//  s="1+((2+3)×4)-5";
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++; //i需要后移
        } else { //如果是一个数,需要考虑多位数
            str = ""; //先将str 置成"" '0'[48]->'9'[57]
            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;//返回
}

以上是关于Java数据结构—前缀中缀波兰表达式的主要内容,如果未能解决你的问题,请参考以下文章

前缀中缀后缀表达式(逆波兰表达式)

前缀中缀后缀表达式(逆波兰表达式)

栈实现综合计算器(中缀表达式),前缀,中缀,后缀表达式,逆波兰计算器

前缀中缀后缀表达式以及简单计算器的实现

中缀表达式转为后缀表达式(逆波兰式)求值

中缀表达式转为后缀表达式(逆波兰式)求值