【數(shù)據(jù)結(jié)構(gòu)與算法】逆波蘭表達式、波蘭表達式

前言

看這篇文章之前袱箱,我們先要明確一些概念庆揪。

1.前綴表達式又稱波蘭式式曲,前綴表達式的運算符位于操作數(shù)之前。比如:- × + 3 4 5 6
2.中綴表達式就是常見的運算表達式缸榛,如(3+4)×5-6
3.后綴表達式又稱逆波蘭表達式,與前綴表達式相似吝羞,只是運算符位于操作數(shù)之后,比如:3 4 + 5 × 6 -

人類最熟悉的一種表達式1+2,(1+2)3仔掸,3+42+4等都是中綴表示法脆贵。對于人們來說,也是最直觀的一種求值方式起暮,先算括號里的卖氨,然后算乘除筒捺,最后算加減系吭,但是,計算機處理中綴表達式卻并不方便则吟。

然后我們還需明確一些概念,下面通過我們最熟悉的中綴表達式畫出一棵語法樹來直觀認識一下前后綴表達式的生成敬扛。以A+B*(C-D)-E*F為例:

image

中綴表達式得名于它是由相應(yīng)的語法樹的中序遍歷的結(jié)果得到的谍珊。上面的二叉樹中序遍歷的結(jié)果就是A+B*(C-D)-E*F

前綴表達式是由相應(yīng)的語法樹的前序遍歷的結(jié)果得到的。上圖的前綴表達式為- + A * B - C D * E F

后綴表達式又叫做逆波蘭式陕悬。它是由相應(yīng)的語法樹的后序遍歷的結(jié)果得到的。上圖的后綴表達式為:A B C D - * + E F * -

下面我們關(guān)注兩個點:
1.如何根據(jù)一個逆波蘭表達式求出運算結(jié)果?
2.如果將一個中綴表達式轉(zhuǎn)換成后綴表達式(逆波蘭表達式)

一.通過逆波蘭表達式計算結(jié)果

我們先看一個例子...后綴表達式3 4 + 5 × 6 -的計算
1.從左至右掃描,將3和4壓入堆棧耐版;
2.遇到+運算符,因此彈出4和3(4為棧頂元素腺阳,3為次頂元素,注意與前綴表達式做比較)痛侍,計算出3+4的值赵哲,得7,再將7入棧;
3.將5入棧扒最;
4.接下來是×運算符,因此彈出5和7强挫,計算出7×5=35,將35入棧;
5.將6入棧;
6.最后是-運算符劝萤,計算出35-6的值,即29,由此得出最終結(jié)果缆娃。

從上面的過程我們?nèi)绾尉帉懘a實現(xiàn)呢椭住?

可以采用一個輔助的棧來實現(xiàn)計算,掃描表達式從左往右進行,如果掃描到數(shù)值兽肤,則壓進輔助棧中,如果掃描到運算符绪抛,則從輔助棧中彈出兩個數(shù)值參與運算,并將結(jié)果壓進到棧中电禀,當掃描表達式結(jié)束后幢码,棧頂?shù)臄?shù)值就是表達式結(jié)果。

下面是代碼實現(xiàn)(Java)

 /**
     * 通過逆波蘭表達式計算結(jié)果
     * @param ls
     * @return
     */
     //求逆波蘭表達式的值
    public static int calcRevPolishNotation(String express){
        Stack<String> stack = new Stack<>();
        for (int i = 0; i <express.length() ;i++) {
            // 普通數(shù)值的處理
            if ((express.charAt(i) + "").matches("\\d")){
                stack.push(express.charAt(i) + "");
            // + - * / 運算符的處理
            }else if ((express.charAt(i) + "").matches("[\\+\\-\\*\\/]")){
                String k1 = stack.pop();
                String k2 = stack.pop();
                // 計算結(jié)果
                int res = calcValue(k1, k2, (express.charAt(i) + ""));
                stack.push(res+"");
            }

        }
        return Integer.valueOf(stack.pop());
    }

     //根據(jù)運算符計算結(jié)果
    private static int calcValue(String k1, String k2, String c) {
        switch(c){
            case "+":
                return Integer.valueOf(k1)+Integer.valueOf(k2);
            case "-":
                return Integer.valueOf(k2)-Integer.valueOf(k1);
            case "*":
                return Integer.valueOf(k1)*Integer.valueOf(k2);
            case "/":
                return Integer.valueOf(k2)/Integer.valueOf(k1);
            default:
                throw new RuntimeException("沒有該類型的運算符尖飞!");
        }
    }

二.中綴表達式轉(zhuǎn)換為后綴表達式(逆波蘭表達式)

中綴表達式轉(zhuǎn)后綴表達式主要用到了棧進行運算符處理症副,隊列進行排序輸出,規(guī)則為:

1.數(shù)字直接入隊列
2.運算符要與棧頂元素比較
?①棧為空直接入棧
?②運算符優(yōu)先級大于棧頂元素優(yōu)先級則直接入棧
?③小于或等于則出棧入列政基,再與棧頂元素進行比較贞铣,直到運算符優(yōu)先級小于棧頂元
????素優(yōu)先級后,操作符再入棧
3.操作符是 ( 則無條件入棧
4.操作符為 )沮明,則依次出棧入列辕坝,直到匹配到第一個(為止,此操作符直接舍棄荐健,(直接出棧舍棄

代碼實現(xiàn)(Java)

/**
     * 將中綴表達式轉(zhuǎn)換為后綴表達式(逆波蘭表達式)
     * @param express
     * @return
     */
    public static String transfer(String express){
        Stack<String> stack = new Stack<>();
        List<String> list= new ArrayList<>();
        for (int i=0;i<express.length();i++){
            if ((express.charAt(i)+"").matches("\\d")){
                list.add(express.charAt(i)+"");
            }else if((express.charAt(i)+"").matches("[\\+\\-\\*\\/]")){
                //如果stack為空
                if (stack.isEmpty()){
                    stack.push(express.charAt(i)+"");
                    continue;
                }
                //不為空

                //上一個元素不為(酱畅,且當前運算符優(yōu)先級小于上一個元素則,將比這個運算符優(yōu)先級大的元素全部加入到隊列中
                while (!stack.isEmpty()&&!stack.lastElement().equals("(")&&!comparePriority(express.charAt(i)+"",stack.lastElement())){
                    list.add(stack.pop());
                }
                stack.push(express.charAt(i)+"");
            }else if(express.charAt(i)=='('){
                //遇到左小括號無條件加入
                stack.push(express.charAt(i) + "");
            }else if(express.charAt(i)==')'){
                //遇到右小括號江场,則尋找上一堆小括號纺酸,然后把中間的值全部放入隊列中
                while(!("(").equals(stack.lastElement())){
                    list.add(stack.pop());
                }
                //上述循環(huán)停止,這棧頂元素必為"("
                stack.pop();
            }
        }
        //將棧中剩余元素加入到隊列中
        while (!stack.isEmpty()){
            list.add(stack.pop());
        }
        StringBuffer stringBuffer = new StringBuffer();
        //變成字符串
        for (String s : list) {
            stringBuffer.append(s);
        }
        return stringBuffer.toString();
    }

    /**
     * 比較運算符的優(yōu)先級
     * @param o1
     * @param o2
     * @return
     */
    public static boolean comparePriority(String o1,String o2){
        return getPriorityValue(o1)>getPriorityValue(o2);
    }

    /**
     * 獲得運算符的優(yōu)先級
     * @param str
     * @return
     */
    private static int getPriorityValue(String str) {
        switch(str){
            case "+":
                return 1;
            case "-":
                return 1;
            case "*":
                return 2;
            case "/":
                return 2;
            default:
                throw new RuntimeException("沒有該類型的運算符址否!");
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末餐蔬,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌樊诺,老刑警劉巖仗考,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異啄骇,居然都是意外死亡痴鳄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門缸夹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痪寻,“玉大人,你說我怎么就攤上這事虽惭∠鹄啵” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵芽唇,是天一觀的道長顾画。 經(jīng)常有香客問我,道長匆笤,這世上最難降的妖魔是什么研侣? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮炮捧,結(jié)果婚禮上庶诡,老公的妹妹穿的比我還像新娘。我一直安慰自己咆课,他們只是感情好末誓,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著书蚪,像睡著了一般喇澡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上殊校,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天晴玖,我揣著相機與錄音,去河邊找鬼为流。 笑死窜醉,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的艺谆。 我是一名探鬼主播榨惰,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼静汤!你這毒婦竟也來了琅催?” 一聲冷哼從身側(cè)響起居凶,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎藤抡,沒想到半個月后侠碧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡缠黍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年弄兜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓷式。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡替饿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贸典,到底是詐尸還是另有隱情视卢,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布廊驼,位于F島的核電站据过,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妒挎。R本人自食惡果不足惜绳锅,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酝掩。 院中可真熱鬧鳞芙,春花似錦、人聲如沸庸队。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彻消。三九已至,卻和暖如春宙拉,著一層夾襖步出監(jiān)牢的瞬間宾尚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工谢澈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留煌贴,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓锥忿,卻偏偏與公主長得像牛郑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子敬鬓,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350