逆波蘭表達(dá)式

百度百科

??逆波蘭表達(dá)式又叫做后綴表達(dá)式奋渔。在通常的表達(dá)式中张足,二元運(yùn)算符總是置于與之相關(guān)的兩個(gè)運(yùn)算對(duì)象之間笨枯,這種表示法也稱(chēng)為中綴表示蛙讥。波蘭邏輯學(xué)家J.Lukasiewicz于1929年提出了另一種表示表達(dá)式的方法锯蛀,按此方法,每一運(yùn)算符都置于其運(yùn)算對(duì)象之后次慢,故稱(chēng)為后綴表示旁涤。

用途

??逆波蘭表達(dá)式是一種十分有用的表達(dá)式,它將復(fù)雜表達(dá)式轉(zhuǎn)換為可以依靠簡(jiǎn)單的操作得到計(jì)算結(jié)果的表達(dá)式迫像。例如(a+b)(c+d)轉(zhuǎn)換為ab+cd+

優(yōu)勢(shì)

??它的優(yōu)勢(shì)在于只用兩種簡(jiǎn)單操作劈愚,入棧和出棧就可以搞定任何普通表達(dá)式的運(yùn)算。其運(yùn)算方式如下:
??如果當(dāng)前字符為變量或者為數(shù)字侵蒙,則壓棧造虎,如果是運(yùn)算符,則將棧頂兩個(gè)元素彈出作相應(yīng)運(yùn)算纷闺,結(jié)果再入棧算凿,最后當(dāng)表達(dá)式掃描完后,棧里的就是結(jié)果犁功。

運(yùn)算方法

1.創(chuàng)建兩個(gè)棧氓轰,一個(gè)用來(lái)存放運(yùn)算符stack1,一個(gè)用來(lái)存放最終結(jié)果stack2浸卦,遍歷字符串署鸡;
a>如果是數(shù)字,直接壓入stack2限嫌;
b>如果是是運(yùn)算符且棧為空靴庆,直接壓入stack1,如果棧不為空怒医,當(dāng)前運(yùn)算符與棧頂運(yùn)算符比較炉抒,如果優(yōu)先級(jí)高于棧頂運(yùn)算符直接壓入,小于等于則稚叹,先把小于等于部分的運(yùn)算符彈出到stack2中焰薄,再把掃描到的運(yùn)算符壓入到stack1中拿诸;
c>如果是'(',則無(wú)條件入棧,當(dāng)遇到')'的時(shí)候塞茅,直接把括號(hào)內(nèi)的部分彈出到stack2中亩码,且括號(hào)不能入棧,輸出的棧中是沒(méi)有括號(hào)這個(gè)運(yùn)算符的野瘦;

舉例說(shuō)明

a+bc +(d-e)f,運(yùn)算符棧為s1,存放輸出結(jié)果的棧為s2描沟;

1.遇到數(shù)字a,直接入棧s2;此時(shí)s1:null ?;? s2:a

2.遇到+號(hào)且s1為空鞭光,直接入棧s1;此時(shí):s1:+?;? s2:a

3.遇到數(shù)字b啊掏,直接入棧s2;此時(shí):s1:+?;? s2:ab

4.遇到*號(hào),優(yōu)先級(jí)高于+號(hào)衰猛,直接入棧s1;此時(shí):s1:+* ?;? s2:ab

5.遇到數(shù)字b,直接入棧s2;此時(shí):s1:+* ?;? s2:abc

6.遇到+號(hào),且運(yùn)算符優(yōu)先級(jí)低于s1棧頂符號(hào)刹孔,號(hào)彈出到s2;此時(shí):s1:+ ?;? s2:abc;又等于此時(shí)s1的棧頂元素+號(hào)啡省,繼續(xù)彈出到s2;此時(shí):s1:null ?;? s2:abc+;然后把+號(hào)直接壓入s1;此時(shí):s1:+ ?;? s2:abc*+

7.遇到(的時(shí)候,無(wú)條件壓入s1;此時(shí):s1:+( ?;? s2:abc*+

8.遇到d的時(shí)候髓霞,壓入s2;此時(shí):s1:+( ?;? s2:abc*+d

9.遇到-號(hào)的時(shí)候,壓入s1;此時(shí):s1:+(- ?;? s2:abc*+

10.遇到e的時(shí)候搬卒,直接壓入s2弯院;此時(shí):s1:+(- ?;? s2:abc*+e

11.遇到)的時(shí)候,把括號(hào)內(nèi)部分還存在的運(yùn)算符壓入到 s2;此時(shí):s1:+?;? s2:abc*+-

12.遇到號(hào)的時(shí)候纵潦,運(yùn)算符優(yōu)先級(jí)比s1棧頂元素+號(hào)高徐鹤,直接壓入s1;此時(shí):s1:+?;? s2:abc*+-

13.遇到數(shù)字f直接壓入s2;此時(shí):s1:+?;? s2:abc+-f

14.此時(shí)把s1中的運(yùn)算符號(hào)依次壓入到s2;此時(shí):s1:null ?;? s2:abc+-f+

此時(shí),一個(gè)運(yùn)算結(jié)束邀层,其他表達(dá)式同樣的操作進(jìn)行即可返敬;

代碼實(shí)現(xiàn)

import java.util.Stack;

/**
 * 逆波蘭表達(dá)式
 */
public class ReversePolishNotation {
    public static void main(String[] args) {
        //測(cè)試用例
        //String str = "1+2*3-4*5-6+7*8-9"; //123*+45*-6-78*+9-
        String str = "a*(b-c*d)+e-f/g*(h+i*j-k)"; // abcd*-*e+fg/hij*+k-*-
        //String str = "6*(5+(2+3)*8+3)"; //6523+8*+3+*
        //String str = "a+b*c+(d*e+f)*g"; //abc*+de*f+g*f

        Stack<Character> operators = new Stack<>(); //運(yùn)算符
        Stack output = new Stack(); //輸出結(jié)果
        rpn(operators, output, str);
        System.out.println(output);
    }

    public static void rpn(Stack<Character> operators, Stack output, String str) {
        char[] chars = str.toCharArray();
        int pre = 0;
        boolean digital; //是否為數(shù)字(只要不是運(yùn)算符,都是數(shù)字)寥院,用于截取字符串
        int len = chars.length;
        int bracket = 0; // 左括號(hào)的數(shù)量

        for (int i = 0; i < len; ) {
            pre = i;
            digital = Boolean.FALSE;
            //截取數(shù)字
            while (i < len && !Operator.isOperator(chars[i])) {
                i++;
                digital = Boolean.TRUE;
            }

            if (digital) {
                output.push(str.substring(pre, i));
            } else {
                char o = chars[i++]; //運(yùn)算符
                if (o == '(') {
                    bracket++;
                }
                if (bracket > 0) {
                    if (o == ')') {
                        while (!operators.empty()) {
                            char top = operators.pop();
                            if (top == '(') {
                                break;
                            }
                            output.push(top);
                        }
                        bracket--;
                    } else {
                        //如果棧頂為 ( 劲赠,則直接添加,不顧其優(yōu)先級(jí)
                        //如果之前有 ( 秸谢,但是 ( 不在棧頂凛澎,則需判斷其優(yōu)先級(jí),如果優(yōu)先級(jí)比棧頂?shù)牡凸捞悖瑒t依次出棧
                        while (!operators.empty() && operators.peek() != '(' && Operator.cmp(o, operators.peek()) <= 0) {
                            output.push(operators.pop());
                        }
                        operators.push(o);
                    }
                } else {
                    while (!operators.empty() && Operator.cmp(o, operators.peek()) <= 0) {
                        output.push(operators.pop());
                    }
                    operators.push(o);
                }
            }
        }
        //遍歷結(jié)束塑煎,將運(yùn)算符棧全部壓入output
        while (!operators.empty()) {
            output.push(operators.pop());
        }
    }
}

enum Operator {
    ADD('+', 1), SUBTRACT('-', 1),
    MULTIPLY('*', 2), DIVIDE('/', 2),
    LEFT_BRACKET('(', 3), RIGHT_BRACKET(')', 3); //括號(hào)優(yōu)先級(jí)最高
    char value;
    int priority;

    Operator(char value, int priority) {
        this.value = value;
        this.priority = priority;
    }

    /**
     * 比較兩個(gè)符號(hào)的優(yōu)先級(jí)
     *
     * @param c1
     * @param c2
     * @return c1的優(yōu)先級(jí)是否比c2的高,高則返回正數(shù)元媚,等于返回0轧叽,小于返回負(fù)數(shù)
     */
    public static int cmp(char c1, char c2) {
        int p1 = 0;
        int p2 = 0;
        for (Operator o : Operator.values()) {
            if (o.value == c1) {
                p1 = o.priority;
            }
            if (o.value == c2) {
                p2 = o.priority;
            }
        }
        return p1 - p2;
    }

    /**
     * 枚舉出來(lái)的才視為運(yùn)算符苗沧,用于擴(kuò)展
     *
     * @param c
     * @return
     */
    public static boolean isOperator(char c) {
        for (Operator o : Operator.values()) {
            if (o.value == c) {
                return true;
            }
        }
        return false;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市炭晒,隨后出現(xiàn)的幾起案子待逞,更是在濱河造成了極大的恐慌,老刑警劉巖网严,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件识樱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡震束,警方通過(guò)查閱死者的電腦和手機(jī)怜庸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)垢村,“玉大人割疾,你說(shuō)我怎么就攤上這事〖嗡ǎ” “怎么了宏榕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)侵佃。 經(jīng)常有香客問(wèn)我麻昼,道長(zhǎng),這世上最難降的妖魔是什么馋辈? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任抚芦,我火速辦了婚禮,結(jié)果婚禮上迈螟,老公的妹妹穿的比我還像新娘叉抡。我一直安慰自己,他們只是感情好答毫,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布卜壕。 她就那樣靜靜地躺著,像睡著了一般烙常。 火紅的嫁衣襯著肌膚如雪轴捎。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天蚕脏,我揣著相機(jī)與錄音侦副,去河邊找鬼。 笑死驼鞭,一個(gè)胖子當(dāng)著我的面吹牛秦驯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挣棕,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼译隘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼亲桥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起固耘,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤题篷,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后厅目,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體番枚,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年损敷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了葫笼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拗馒,死狀恐怖路星,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诱桂,我是刑警寧澤奥额,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站访诱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏韩肝。R本人自食惡果不足惜触菜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哀峻。 院中可真熱鬧涡相,春花似錦、人聲如沸剩蟀。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)育特。三九已至丙号,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缰冤,已是汗流浹背犬缨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棉浸,地道東北人怀薛。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像迷郑,于是被迫代替她去往敵國(guó)和親枝恋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子创倔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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