Java數(shù)據(jù)結構和算法(六)——前綴召衔、中綴铃诬、后綴表達式

前面我們介紹了三種數(shù)據(jù)結構,第一種數(shù)組主要用作數(shù)據(jù)存儲苍凛,但是后面的兩種棧和隊列我們說主要作為程序功能實現(xiàn)的輔助工具趣席,其中在介紹棧時我們知道棧可以用來做單詞逆序醇蝴,匹配關鍵字符等等秧倾,那它還有別的什么功能嗎魔种?以及數(shù)據(jù)結構與本篇博客的主題前綴屎蜓、中綴惫周、后綴表達式有什么關系呢?

1惭适、人如何解析算術表達式

如何解析算術表達式笙瑟?或者換種說法,遇到某個算術表達式腥沽,我們是如何計算的:

①逮走、求值 3+4-5

image

這個表達式,我們在看到3+4后都不能直接計算3+4的值,知道看到4后面的 - 號师溅,因為減號的優(yōu)先級和前面的加號一樣茅信,所以可以計算3+4的值了,如果4后面是 * 或者 /墓臭,那么就要在乘除過后才能做加法操作蘸鲸,比如:

②、求值 3+45*

image

這個不能先求3+4的值窿锉,因為4后面的*運算級別比前面的+高酌摇。通過這兩個表達式的說明,我們可以總結解析表達式的時候遵循的幾條規(guī)則:

①嗡载、從左到右讀取算式窑多。

  ②洼滚、已經(jīng)讀到了可以計算值的兩個操作數(shù)和一個操作符時埂息,可以計算,并用計算結果代替那兩個操作數(shù)和一個操作符遥巴。

 ∏Э怠③、繼續(xù)這個過程铲掐,從左到右拾弃,能算就算,直到表達式的結尾摆霉。

2豪椿、計算機如何解析算術表達式

對于前面的表達式 3+4-5,我們?nèi)耸怯兴季S能力的携栋,能根據(jù)操作符的位置砂碉,以及操作符的優(yōu)先級別能算出該表達式的結果。但是計算機怎么算刻两?

計算機必須要向前(從左到右)來讀取操作數(shù)和操作符,等到讀取足夠的信息來執(zhí)行一個運算時滴某,找到兩個操作數(shù)和一個操作符進行運算磅摹,有時候如果后面是更高級別的操作符或者括號時,就必須推遲運算霎奢,必須要解析到后面級別高的運算户誓,然后回頭來執(zhí)行前面的運算。我們發(fā)現(xiàn)這個過程是極其繁瑣的幕侠,而計算機是一個機器帝美,只認識高低電平,想要完成一個簡單表達式的計算晤硕,我們可能要設計出很復雜的邏輯電路來控制計算過程悼潭,那更不用說很復雜的算術表達式庇忌,所以這樣來解析算術表達式是不合理的,那么我們應該采取什么辦法呢舰褪?

請大家先看看什么是前綴表達式皆疹,中綴表達式,后綴表達式:這三種表達式其實就是算術表達式的三種寫法占拍,以 3+4-5為例

①略就、前綴表達式:操作符在操作數(shù)的前面,比如 +-543

②晃酒、中綴表達式:操作符在操作數(shù)的中間表牢,這也是人類最容易識別的算術表達式 3+4-5

③、后綴表達式:操作符在操作數(shù)的后面贝次,比如 34+5-

上面我們講的人是如何解析算術表達式的崔兴,也就是解析中綴表達式,這是人最容易識別的浊闪,但是計算機不容易識別恼布,計算機容易識別的是前綴表達式和后綴表達式,將中綴表達式轉換為前綴表達式或者后綴表達式之后搁宾,計算機能很快計算出表達式的值折汞,那么中綴表達式是如何轉換為前綴表達式和后綴表達式,以及計算機是如何解析前綴表達式和后綴表達式來得到結果的呢盖腿?

3爽待、后綴表達式

后綴表達式,指的是不包含括號翩腐,運算符放在兩個運算對象的后面鸟款,所有的計算按運算符出現(xiàn)的順序,嚴格從左向右進行(不再考慮運算符的優(yōu)先規(guī)則)茂卦。

由于后綴表達式的運算符在兩個操作數(shù)的后面何什,那么計算機在解析后綴表達式的時候,只需要從左向右掃描等龙,也就是只需要向前掃描处渣,而不用回頭掃描,遇到運算符就將運算符放在前面兩個操作符的中間(這里先不考慮乘方類似的單目運算)蛛砰,一直運算到最右邊的運算符罐栈,那么就得出運算結果了。既然后綴表達式這么好泥畅,那么問題來了:

①荠诬、如何將中綴表達式轉換為后綴表達式?

對于這個問題,轉換的規(guī)則如下:

image

一柑贞、先自定義一個棧

package com.ys.poland;

public class MyCharStack {
    private char[] array;
    private int maxSize;
    private int top;
    
    public MyCharStack(int size){
        this.maxSize = size;
        array = new char[size];
        top = -1;
    }
    
    //壓入數(shù)據(jù)
    public void push(char value){
        if(top < maxSize-1){
            array[++top] = value;
        }
    }
    
    //彈出棧頂數(shù)據(jù)
    public char pop(){
        return array[top--];
    }
    
    //訪問棧頂數(shù)據(jù)
    public char peek(){
        return array[top];
    }
    
    //查看指定位置的元素
    public char peekN(int n){
        return array[n];
    }
    
    //為了便于后面分解展示棧中的內(nèi)容方椎,我們增加了一個遍歷棧的方法(實際上棧只能訪問棧頂元素的)
    public void displayStack(){
        System.out.print("Stack(bottom-->top):");
        for(int i = 0 ; i < top+1; i++){
            System.out.print(peekN(i));
            System.out.print(' ');
        }
        System.out.println("");
    }
    
    //判斷棧是否為空
    public boolean isEmpty(){
        return (top == -1);
    }
    
    //判斷棧是否滿了
    public boolean isFull(){
        return (top == maxSize-1);
    }

}

二、前綴表達式轉換為后綴表達式

package com.ys.poland;

public class InfixToSuffix {
    private MyCharStack s1;//定義運算符棧
    private MyCharStack s2;//定義存儲結果棧
    private String input;
    
    //默認構造方法凌外,參數(shù)為輸入的中綴表達式
    public InfixToSuffix(String in){
        input = in;
        s1 = new MyCharStack(input.length());
        s2 = new MyCharStack(input.length());
    }
    //中綴表達式轉換為后綴表達式辩尊,將結果存儲在棧中返回,逆序顯示即后綴表達式
    public MyCharStack doTrans(){
        for(int j = 0 ; j < input.length() ; j++){
            System.out.print("s1棧元素為:");
            s1.displayStack();
            System.out.print("s2棧元素為:");
            s2.displayStack();
            char ch = input.charAt(j);
            System.out.println("當前解析的字符:"+ch);
            switch (ch) {
            case '+':
            case '-':
                gotOper(ch,1);
                break;
            case '*':
            case '/':
                gotOper(ch,2);
                break;
            case '(':
                s1.push(ch);//如果當前字符是'(',則將其入棧
                break;
            case ')':
                gotParen(ch);
                break;
            default:
                //1康辑、如果當前解析的字符是操作數(shù)摄欲,則直接壓入s2
                //2、
                s2.push(ch);
                break;
            }//end switch
        }//end for
        
        while(!s1.isEmpty()){
            s2.push(s1.pop());
        }
        return s2;
    }
    
    public void gotOper(char opThis,int prec1){
        while(!s1.isEmpty()){
            char opTop = s1.pop();
            if(opTop == '('){//如果棧頂是'(',直接將操作符壓入s1
                s1.push(opTop);
                break;
            }else{
                int prec2;
                if(opTop == '+' || opTop == '-'){
                    prec2 = 1;
                }else{
                    prec2 = 2;
                }
                if(prec2 < prec1){//如果當前運算符比s1棧頂運算符優(yōu)先級高疮薇,則將運算符壓入s1
                    s1.push(opTop);
                    break;
                }else{//如果當前運算符與棧頂運算符相同或者小于優(yōu)先級別胸墙,那么將S1棧頂?shù)倪\算符彈出并壓入到S2中
                    //并且要再次再次轉到while循環(huán)中與 s1 中新的棧頂運算符相比較;
                    s2.push(opTop);
                }
            }
            
        }//end while
        //如果s1為空按咒,則直接將當前解析的運算符壓入s1
        s1.push(opThis);
    }
    
    //當前字符是 ')' 時,如果棧頂是'(',則將這一對括號丟棄励七,否則依次彈出s1棧頂?shù)淖址窍瑝喝雜2,直到遇到'('
    public void gotParen(char ch){
        while(!s1.isEmpty()){
            char chx = s1.pop();
            if(chx == '('){
                break;
            }else{
                s2.push(chx);
            }
        }
    }

}

三掠抬、測試

@Test
public void testInfixToSuffix(){
    String input;
    System.out.println("Enter infix:");
    Scanner scanner = new Scanner(System.in);
    input = scanner.nextLine();
    InfixToSuffix in = new InfixToSuffix(input);
    MyCharStack my = in.doTrans();
    my.displayStack();
}

四吼野、結果

image

五、分析

image

②两波、計算機如何實現(xiàn)后綴表達式的運算瞳步?

image
package com.ys.poland;

public class CalSuffix {
    private MyIntStack stack;
    private String input;
    
    public CalSuffix(String input){
        this.input = input;
        stack = new MyIntStack(input.length());
        
    }
    
    public int doCalc(){
        int num1,num2,result;
        for(int i = 0 ; i < input.length() ; i++){
            char c = input.charAt(i);
            if(c >= '0' && c <= '9'){
                stack.push((int)(c-'0'));//如果是數(shù)字,直接壓入棧中
            }else{
                num2 = stack.pop();//注意先出來的為第二個操作數(shù)
                num1 = stack.pop();
                switch (c) {
                case '+':
                    result = num1+num2;
                    break;
                case '-':
                    result = num1-num2;
                    break;
                case '*':
                    result = num1*num2;
                    break;
                case '/':
                    result = num1/num2;
                    break;
                default:
                    result = 0;
                    break;
                }//end switch
                
                stack.push(result);
            }//end else
        }//end for
        result = stack.pop();
        return result;
    }
    
    public static void main(String[] args) {
        //中綴表達式:1*(2+3)-5/(2+3) = 4
        //后綴表達式:123+*123+/-
        CalSuffix cs = new CalSuffix("123+*523+/-");
        System.out.println(cs.doCalc()); //4
    }

}

4腰奋、前綴表達式

前綴表達式单起,指的是不包含括號,運算符放在兩個運算對象的前面劣坊,嚴格從右向左進行(不再考慮運算符的優(yōu)先規(guī)則)嘀倒,所有的計算按運算符出現(xiàn)的順序。

注意:后綴表達式是從左向右解析局冰,而前綴表達式是從右向左解析括儒。

①、如何將中綴表達式轉換為前綴表達式锐想?

image

②、計算機如何實現(xiàn)前綴表達式的運算乍狐?

image

參考文檔:http://blog.csdn.net/antineutrino/article/details/6763722/

參考書籍:《Java數(shù)據(jù)結構和算法》

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赠摇,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌藕帜,老刑警劉巖烫罩,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異洽故,居然都是意外死亡贝攒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門时甚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隘弊,“玉大人,你說我怎么就攤上這事荒适±嫖酰” “怎么了?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵刀诬,是天一觀的道長咽扇。 經(jīng)常有香客問我,道長陕壹,這世上最難降的妖魔是什么质欲? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮糠馆,結果婚禮上嘶伟,老公的妹妹穿的比我還像新娘。我一直安慰自己榨惠,他們只是感情好奋早,可當我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赠橙,像睡著了一般耽装。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上期揪,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天掉奄,我揣著相機與錄音,去河邊找鬼凤薛。 笑死姓建,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的缤苫。 我是一名探鬼主播速兔,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼活玲!你這毒婦竟也來了涣狗?” 一聲冷哼從身側響起谍婉,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎镀钓,沒想到半個月后穗熬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡丁溅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年唤蔗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窟赏。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡妓柜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饰序,到底是詐尸還是另有隱情领虹,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布求豫,位于F島的核電站塌衰,受9級特大地震影響,放射性物質發(fā)生泄漏蝠嘉。R本人自食惡果不足惜最疆,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蚤告。 院中可真熱鬧努酸,春花似錦、人聲如沸杜恰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽心褐。三九已至舔涎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逗爹,已是汗流浹背亡嫌。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掘而,地道東北人挟冠。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像袍睡,于是被迫代替她去往敵國和親知染。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容