【数据结构和算法分析】栈与逆波兰式

来源:互联网 发布:windows server官网 编辑:程序博客网 时间:2024/05/16 17:22

栈ADT

:是限制插入和删除只能在一个位置上进行的表,该位置就是表的末端,或者栈的顶端(top)。对栈的基本操作有 push(进栈) 和 pop(出栈)。注意,对空栈进行的 pop 或 top 操作一般被认为是栈ADT的一个错误。另一方面,当运行 push 时空间用尽是一个实现限制,但不是ADT错误


栈的实现:由于栈是一个表,因此任何实现表的方法都能实现栈,所以在 java 中 ArrayList 和 LinkedList 都支持栈操作,99%的时间它们都是最合理的选择。栈的优势在于它的操作不仅是以常数时间运行,而且是以非常快的常数时间运行。即使是这样简单的结构与功能,却有着非常强大的作用

为了简单,用 ArrayList 实现一个具有基本功能的 MyStack

import java.util.ArrayList;public class MyStack {private ArrayList<Object> stack = new ArrayList<>();public MyStack(){}/* * 进栈 */public void push(Object object){    stack.add(object);}/* * 出栈 */public void pop(){if (stack.size() == 0) {throw new IndexOutOfBoundsException();}else{stack.remove(stack.size()-1);}}/* * 返回栈顶元素 */public Object top(){if (stack.size() == 0) {throw new IndexOutOfBoundsException();}else{return stack.get(stack.size()-1);}}    public int length(){return stack.size();}}


栈的应用

中缀表达式转后缀表达式

中缀表达式即标准形式的表达式。我们通过只允许操作+,-,*,/,(,),并坚持普通的优先级法则而将一般的问题浓缩成小规模的问题,比如,将中缀表达式 a + b * c + ( d * e + f ) * g  转换为后缀表达式就是 a b c * + d e * f + g * +

解法

1.遇到操作数,直接输出(添加到后缀表达式中)

2.栈为空时,遇到运算符,直接入栈

3.遇到左括号,将其入栈

4.遇到右括号,执行出栈操作,并将出栈的元素依次输出,直至弹出的是左括号,左括号不输出

5.遇到其他的运算符,加减乘除,依次弹出运算符优先级大于或者等于该运算符的的栈顶元素,然后将该运算符入栈

6.最终将栈内的元素依次出栈,输出


逆波兰式求值

逆波兰式,即后缀表达式

解法

从左往右扫描表达式,遇到数字时,将数字压入栈中,遇到运算符时,将栈顶的两个元素弹出,用运算符对它们进行相应的操作,并将结果入栈;重复上述步骤,到表达式扫描结束,最后运算得到的结果就是原表达式的结果。


附上代码:

import java.util.Stack;import java.util.regex.Pattern;public class PostFix {private static String infixToSuffix(String infix) {Stack<Character> stack = new Stack<Character>();String suffix = "";int length = infix.length();for (int i = 0; i < length; i++) {Character temp;char c = infix.charAt(i);switch (c) {// 忽略空格case ' ':break;// 碰到'(',push到栈case '(':stack.push(c);break;// 碰到'+''-',将栈中所有运算符弹出,送到输出队列中case '+':case '-':while (stack.size() != 0) {temp = stack.pop();if (temp == '(') {stack.push('(');break;}suffix += " " + temp;}stack.push(c);suffix += " ";break;// 碰到'*''/',将栈中所有乘除运算符弹出,送到输出队列中case '*':case '/':while (stack.size() != 0) {temp = stack.pop();if (temp == '(' || temp == '+' || temp == '-') {stack.push(temp);break;} else {suffix += " " + temp;}}stack.push(c);suffix += " ";break;// 碰到右括号,将靠近栈顶的第一个左括号上面的运算符全部依次弹出,送至输出队列后,再丢弃左括号case ')':while (stack.size() != 0) {temp = stack.pop();if (temp == '(')break;elsesuffix += " " + temp;}break;default:suffix += c;}}while (stack.size() != 0)suffix += " " + stack.pop();return suffix;}// 通过后缀表达式求出算术结果private static double suffixToArithmetic(String postfix) {Pattern pattern = Pattern.compile("\\d+||(\\d+\\.\\d+)"); // 匹配数字String strings[] = postfix.split(" ");for (int i = 0; i < strings.length; i++)strings[i].trim();Stack<Double> stack = new Stack<Double>();for (int i = 0; i < strings.length; i++) {if (strings[i].equals(""))continue;if ((pattern.matcher(strings[i])).matches()) {stack.push(Double.parseDouble(strings[i]));} else {double y = stack.pop();double x = stack.pop();stack.push(caculate(x, y, strings[i]));}}return stack.pop();}private static double caculate(double x, double y, String simble) {if (simble.trim().equals("+"))return x + y;if (simble.trim().equals("-"))return x - y;if (simble.trim().equals("*"))return x * y;if (simble.trim().equals("/"))return x / y;return 0;}public static void main(String args[]) {System.out.println(infixToSuffix("2+(5-2*2)*3"));System.out.println(suffixToArithmetic(infixToSuffix("2+(5-2*2)*3")));}}


0 0