中綴表達式轉后綴表達式(代碼實現)及前綴表達式思路補充


  后綴表達式適合計算機式的計算,因此在開發中,我們需要將中綴表達式轉為后綴表達式。

三種表達式

  這里再次區分一下前綴表達式、中綴表達式、后綴表達式(以(3+4)*5-6為例)

  中綴表達式就是我們正常遇見的(3+4)*5-6這樣的式子

  前綴表達式又稱為波蘭式,其運算符是在數之前

  中綴表達式轉前綴表達式思路:從右至左掃描表達式,遇到數字時,將數字壓入堆棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(棧頂元素 top 次頂元素),並將結果入棧;重復上述過程直到表達式最左端,最后運算得出的值即為表達式的結果

  例如:- * + 3 4 5 6

  1. 從右至左掃描,將6、5、4、3壓入堆棧
  2. 遇到+運算符,因此彈出3和4(3為棧頂元素,4為次頂元素,注意與后綴表達式做比較),計算出3+4的值,得7,再將7入棧
  3. 接下來是×運算符,因此彈出7和5,計算出7×5=35,將35入棧
  4. 最后是-運算符,計算出35-6的值,即29,由此得出最終結果

中綴表達式轉后綴表達式具體步驟

    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 -"

過程如下:

 

 舉例代碼

package com.atxihua;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolandNotation1 {
    public static void main(String[] args) {
        //完成將一個中綴表達式轉成后綴表達式的功能
        //1+((2+3)*4)-5轉成1 2 3 + 4 * + 5 -
        //因為直接對str進行操作,不方便,因此,先將1+((2+3)*4)-5存入對應的list
        //即1+((2+3)*4)-5=》ArrayList[1,+,(,(,2,+,3,),*,4),-,5]
        //將得到的中綴表達式對應的List=》后綴表達式對應的List
        //即ArrayList[1,+,(,(,2,+,3,),*,4),-,5]=>ArrayList[1,2,3,+,4,*,+,5,-]
        String expression="1+((2+3)*4)-5";
        List<String> infixExpreesionList=toInfixExpreesionList(expression);
        System.out.println("中綴表達式="+infixExpreesionList);//ArrayList[1,+,(,(,2,+,3,),*,4),-,5]
        List<String> suffixExpreesionList=parseSuffixExpreesionList(infixExpreesionList);
        System.out.println("后綴表達式="+suffixExpreesionList);//ArrayList[1,2,3,+,4,*,+,5,-]
        System.out.println("結果為:"+calculate(suffixExpreesionList));
    }
    //將中綴表達式轉成對應的list
    private static List<String> toInfixExpreesionList(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++;
            }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;
    }
    //將得到的中綴表達式對應的List=>后綴表達式
    private static List<String> parseSuffixExpreesionList(List<String> ls) {
        //定義兩個棧
        Stack<String> s1=new Stack<String>();//符號棧
        //說明:s2這個棧,在整個轉換過程中,沒有pop操作,而且后面需要逆序輸出,就不使用棧,直接使用list存儲
        //Stack<String> s2=new Stack<String>();//數棧
        List<String> s2=new ArrayList<String>();//存儲中間結果的list
        //遍歷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,直到遇到左括號為止,此時將這一對括號丟棄
                //我們缺少一個比較優先級高低的方法
                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;//
    }


    private static int calculate(List<String> ls) {
        //創建一個棧
        Stack<String> stack = new Stack<String>();
        //遍歷ls
        for(String item:ls){
            //使用正則表達式來取數
            if(item.matches("\\d+")){
                //匹配多為數
                //入棧
                stack.push(item);
            }else {
                //pop出兩個數並運算,再入棧
                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("-")){
                    //注意num2比num1先出棧,所以是num1-num2
                    res=num1-num2;
                }else if(item.equals("/")){
                    res=num1/num2;
                }else if(item.equals("*")){
                    res= num1*num2;
                }else {
                    throw new RuntimeException("運算符有誤");
                }
                //把res入棧
                stack.push(""+res);
            }
        }
    //最后留在stack中的數據即運算結果
        return Integer.parseInt(stack.pop());
    }
}
//編寫一個類Operation可以返回一個運算符,對應的優先級
class Operation{
    private static int Add=1;
    private static int SUB=1;
    private static int MUL=2;
    private static int DIV=2;
    //寫一個方法,返回對應的優先級數字
    public static int getValue(String operation){
        int result=0;
        if(operation.equals("+")){
            result=Add;
        }else if(operation.equals("-")){
            result=SUB;
        }else if(operation.equals("*")){
            result=MUL;
        }else if(operation.equals("/")){
            result=DIV;
        }else {
            System.out.println("不存在該運算符");
        }
        return result;
    }
}

運行結果

 

 因為我們在寫代碼時,遇到左括號時,壓入棧中,在遇到右括號時在處理,因此,計算機將左括號當作運算符處理,在處理邏輯中只對加減乘除進行了處理,相信這點很容易理解,就不再處理了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM