Loading

基础计算机器的实现(栈的应用)

基础计算器的实现(栈的应用) :

中缀表达式 转变成 后缀表达式(逆波兰表达式):

中缀表达式:不适合使用程序进行计算;

特别要注意的是:整个过程序需要两个栈,第一个栈是 运算符栈, 第二个栈是 存储中间结果的栈;

流程

1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;

2.从左至右扫描中缀表达式;

3.遇到操作数时,将其压s2;(没有任何异议)

4.遇到运算符时,比较其与s1栈顶运算符的优先级:

  1. 如果s1为空,或栈顶运算符为左括号“(”,则将此运算符直接入栈
  2. 否则,若当前运算符优先级比栈顶运算符的高,也将运算符压入s1(疑问点: 注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
  3. 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;

5.遇到括号时:

  1. 如果是左括号“(”,则直接压入s1;
  2. 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃

6.重复步骤2至5,直到表达式的最右边;

7.将s1中剩余的运算符依次弹出并压入s2;

8.依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)

例如,将中缀表达式“1+((2+3)×4)-5”转换为后缀表达式的过程如下:

因此结果为:1 2 3 + 4 × + 5 -

62f6091_b.jpg)

来源:知乎

1+((2+3)×4)-5 转换为逆波兰表达式过程解释说明:

流程解释:

遇到 1 将操作数放置到 中间结果栈中 ;

​ 运算符栈:S1=>[] , 中间结果栈:backExp=>[1]

遇到 + 将运算符放置到 运算符栈中。

​ 运算符栈:S1=>[ + ] , 中间结果栈:backExp=>[ 1 ]

遇到 ( 将( 直接放入运算符栈。

​ 运算符栈:S1=>[ + ( ] , 中间结果栈:backExp=>[ 1 ]

遇到 ( 将( 直接放入运算符栈。

​ 运算符栈:S1=>[ + ( ( ] , 中间结果栈:backExp=>[ 1 ]

遇到 2 将2直接放入中间结果栈。 =>(因为运算符栈顶是“左括号”)

​ 运算符栈:S1=>[ + ( ( ] , 中间结果栈:backExp=>[ 1 2 ]

遇到 + 将+直接放入运算符栈。 =>(因为运算符栈顶是“左括号”)

​ 运算符栈:S1=>[ + ( ( +] , 中间结果栈:backExp=>[ 1 2 ]

遇到 3 将3直接放入中间结果栈。

​ 运算符栈:S1=>[ + ( ( +] , 中间结果栈:backExp=>[ 1 2 3 ]

遇到 ) , 依次弹出 栈中元素 并加入 中间结果栈中, 并且删除 ()

​ 运算符栈:S1=>[ + ( ] , 中间结果栈:backExp=>[ 1 2 3 +]

遇到 * , 栈顶为左括号,直接入栈

​ 运算符栈:S1=>[ + ( * ] , 中间结果栈:backExp=>[ 1 2 3 +]

遇到 4 , 操作数直接入中间结果栈

​ 运算符栈:S1=>[ + ( * ] , 中间结果栈:backExp=>[ 1 2 3 + 4 ]

到 ) , 依次弹出 栈中元素 并加入 中间结果栈中, 并且删除 ()

​ 运算符栈:S1=>[ + ] , 中间结果栈:backExp=>[ 1 2 3 + 4 * ]

到 - , 依次弹出 优先级比 减号不低的 运算符 ,然后入栈;

​ 运算符栈:S1=>[ - ] , 中间结果栈:backExp=>[ 1 2 3 + 4 * +]

最后,将运算符栈中的元素,依次弹出到中间结果栈;中间结果栈依次弹出,其逆序就是逆波兰表达式(后缀表达式)

​ 运算符栈:S1=>[] , 中间结果栈:backExp=>[ 1 2 3 + 4 * + - ]

逆波兰表达式源码实现(不支持括号):

public class Solution{
    public int calculate(String exp) {
        return calResult(backTempExp(exp));
    }
    // 计算后缀表达式
    public LinkedList<String> backTempExp(String exp) {
        Stack<String> s1 = new Stack<String> ();
        LinkedList backExpr = new LinkedList();
        for(int i = 0; i < exp.length(); i++ ) {
            if(Character.isDigit(exp.charAt(i))) {
                int k = i+1;
                while(k < exp.length() && Character.isDigit(exp.charAt(k)))
                    k++;
                backExpr.addLast(exp.substring(i,k));    // 注意这个api 是前开后闭的区间
                //ystem.out.println(exp.substring(i,k));
                i = k-1;//需要回退一格
                continue;
            }
            if(exp.charAt(i) == '+' || exp.charAt(i)=='-') {
                while(!s1.isEmpty()) {
                    backExpr.addLast(s1.pop());
                }
                s1.push(""+exp.charAt(i));
                continue;
            }
            if(exp.charAt(i) =='*'||exp.charAt(i)=='/' ) {
                // if(!s1.isEmpty())
                //    System.out.println("s1.peek():"+ s1.peek());
                while(!s1.isEmpty() && (s1.peek().equals("*") || s1.peek().equals("/")) ) {
                    //System.out.println("s1.peek():"+ s1.peek());
                    backExpr.addLast(s1.pop());
                }
                //System.out.println(""+exp.charAt(i));
                s1.push(""+exp.charAt(i));
            }
        }
        while(!s1.isEmpty()) {
          backExpr.addLast(s1.pop());
        }
        return backExpr;
    }

    int calResult(LinkedList<String> backExpr) {
        // for(String s : backExpr)
        //   System.out.println(s);
        Stack<Integer> stk = new Stack<Integer> ();
        for(String s : backExpr) {
            if(Character.isDigit(s.charAt(0))){
                stk.push(Integer.valueOf(s));
                continue;
            }
            int num1 = stk.pop();
            int num2 = stk.pop();
            switch (s) {
                case "+":stk.push(num1 + num2); break;
                case "-":stk.push(num2 - num1); break;
                case "*":stk.push(num2 * num1); break;
                case "/":stk.push(num2 / num1);
            }
        }
        return stk.peek();
    }
}

支持括号支持逆波兰表达式

特别注意:在运算符栈中呢,先出栈相当于是先访问

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

public class Leetcode227 {
    public static void main(String[] args) {
        Solution s= new Solution();
        String newStr =  " 3+5 / 2 ";   //"1+((2+3)*4)-5";
        int k = s.calculate(newStr);
        System.out.println(newStr + "=" + k);
    }
}
class Solution{
    public int calculate(String exp) {
        return calResult(backTempExp(exp));
    }
    // 计算后缀表达式
    public LinkedList<String> backTempExp(String exp) {
        Stack<String> s1 = new Stack<String> ();
        LinkedList<String> backExpr = new LinkedList<String> ();
        for(int i = 0; i < exp.length(); i++ ) {
            if(Character.isDigit(exp.charAt(i))) {
                int k = i+1;
                while(k < exp.length() && Character.isDigit(exp.charAt(k)))
                    k++;
                backExpr.addLast(exp.substring(i,k));    // 注意这个api 是前开后闭的区间
                i = k-1;//需要回退一格
            }
            else if(exp.charAt(i) == '+' || exp.charAt(i)=='-' || exp.charAt(i) =='*'||exp.charAt(i)=='/' ) {
                while(!s1.empty() && !s1.peek().equals("(") && !compareOperator(exp.charAt(i), s1.peek().charAt(0))) {
                    backExpr.addLast(s1.pop());
                }
                s1.push(String.valueOf(exp.charAt(i)));

            }
            else if(exp.charAt(i) == '(' || exp.charAt(i)==')' ) {
                if(exp.charAt(i) == '(')
                    s1.push(String.valueOf(exp.charAt(i)));
                else{
                    String op = s1.pop();
                    while(!op.equals("(")){
                        //System.out.println(op);
                        backExpr.addLast(op);
                        op = s1.pop();
                    }
                }
            }
            //System.out.println(exp.charAt(i));
        }
        while(!s1.isEmpty()) {
            backExpr.addLast(s1.pop());
        }
        return backExpr;
    }

    boolean compareOperator(Character  a , Character b) {
        int p1 = 0 , p2= 0;
        if(a == '*' || a =='/')
            p1 = 1;
        if(b == '*' || b =='/')
            p2 = 1;
        return p1 > p2;
    }
	//从逆波兰表达式中计算结果:
    int calResult(LinkedList<String> backExpr) {
//         for(String s : backExpr)
//           System.out.println(s);
        Stack<Integer> stk = new Stack<Integer> ();
        for(String s : backExpr) {

            if(Character.isDigit(s.charAt(0))){
                stk.push(Integer.valueOf(s));
            }
            else {
                int num1 = stk.pop();
                int num2 = stk.pop();

                switch (s) {
                    case "+":
                        stk.push(num1 + num2);
                        break;
                    case "-":
                        stk.push(num2 - num1);
                        break;
                    case "*":
                        stk.push(num2 * num1);
                        break;
                    case "/":
                        stk.push(num2 / num1);
                }
            }
        }
        return stk.peek();
    }
}

蒻霁自己的实现(最老的版本)

class Solution {
    public int calculate(String s) {
        if(s==null || s.length() ==0)
            return 0;
        Stack<Integer> nums = new Stack<Integer> ();
        Stack<Character> operator = new Stack<Character> ();
        int i=0;
        while(i < s.length()) {
            while( i < s.length() && s.charAt(i) == ' ')
                i++;
            if(i >= s.length())
              break;
            if(s.charAt(i) <='9' && s.charAt(i) >='0' ) {
                int num  = 0;
                while(i < s.length() && s.charAt(i) >='0' && s.charAt(i) <='9') {
                  num*=10;
                  num += s.charAt(i) -'0';
                  i++;
                }
                nums.push(num);
            }
            else {
                while(!operator.isEmpty() &&
                 (
                   (s.charAt(i) == '+' || s.charAt(i)=='-')  || 
                   ( (s.charAt(i) == '*' || s.charAt(i)=='/') && (operator.peek() == '*' || operator.peek() =='/') )
                 )){
                      Character op =operator.pop();
                      int num1 = nums.pop();
                      int num2 = nums.pop();
                      if(op == '*') {
                          nums.push(num1 * num2);
                          //System.out.println(num1 + "*" + num2 +   " " + (num1 * num2));
                      } else if(op == '/') {
                          nums.push(num2 / num1);
                          //System.out.println(num2 + "/" + num1 +   " " + (num2 / num1));
                      } else if(op == '+') {
                          nums.push(num1 + num2);
                          //System.out.println(num2 + "+" + num1 +   " " + (num2 + num1));
                      } else {
                        nums.push(num2 - num1);
                         //System.out.println(num2 + "-" + num1 +   " " + (num2 - num1));
                      }
                     
                }
                operator.push(s.charAt(i));
                i++;
            }
          }
      while(!operator.isEmpty()) {
          Character ch = operator.pop();
          int num1 = nums.pop();
          int num2 = nums.pop();
          if(ch == '+')
              nums.push(num1 + num2);
          else if(ch == '-')
              nums.push(num2 - num1);
          else if(ch == '*')
              nums.push(num2 * num1);
          else 
              nums.push(num2 / num1);
      }
      return nums.peek();
    }
}

注意:

Character.isDigit() //判断是否是一个字符串
str.substring(start,end) // [start,end);
posted @ 2020-06-19 10:36  Sidewinder  阅读(174)  评论(0)    收藏  举报