1. 程式人生 > >簡單計算機——逆波蘭表達式

簡單計算機——逆波蘭表達式

emp 內部 family -- bool logs 賦值 加減 是否為空

逆波蘭數:逆波蘭數由兩部分組成(操作數,操作符)——是波蘭表達式的一種,即操作符在操作數的後面。

形式:A+B*C-D = ABC*D-;

  (A+B)*C-D = AB+C*D-;

既然我們知道了,後綴表達式那我們表達式是唯一的嗎?我們來看一組數據:

例如:(A+B)*C-D 和 C*(A+B)-D;

很顯然第二個的表達式為:C*AB+D-;雖然對最後的結果無影響,但我們需要知道逆波蘭的多樣性。

註意事項:

1、如果出現1+23 = 123+,該如何判斷它的數值呢?

  可以利用分割符來進行很好的輔助性理解,例如1+23 = 1#23#+,這樣可以完美的解決此問題。

2、存在括號的時候該如何處理?

  其一:是‘(’直接壓入,‘)’時,將兩者之間的運算符彈出,壓入後綴表達式。

  其二:遇到‘(’開辟一個新的運算符棧,‘)’時,當前棧內運算符彈出,壓入後綴表達式。

算法:

1、中綴表達式——逆波蘭表達式的轉變。

  • 準備一個棧一個鏈表,鏈表用來存操作數,棧用來存操作符。
  • 如果為操作數,我們繼續判斷它的下一位是否也為操作數,是——則繼續壓入,否——壓入分隔符(“#”)。同時判斷字符棧中,是否為“*”,“/”,字符彈出,壓入數值鏈表。
  • 如果為操作符,直接壓入字符棧。
  • 如果‘(’,重新開辟一個新字符棧,其它操作相同。
  • 如果‘ )’,將當前字符棧內部的字符逐個彈出,壓入數值鏈表。

2、逆波蘭求值。

  • 準備一個棧,用來逐個求當前值。
  • 依次取出數值鏈表的第一個值。
  • 根據加減乘除運算做出相應的操作,即取出當前棧的前兩個值,做運算符操作。
  • 如果是操作數,我們繼續判斷它的下一位是否也為操作數,是——n*10+char-‘0’,否——壓入棧中;
  • 最後的到棧頂元素,即為運算後的值。

核心代碼:

1、中綴表達式——逆波蘭表達式的轉變。

技術分享
bool is_char(char c)//判斷是否為操作符
{
    return c == - || c == + || c == * || c == /;
}

void change()//表達式的轉化
{
    char c;
    int
i = 0, j = 0;//i遍歷輸入的字符,j不同層數的字符棧 while ((c = original[i++]) != \0) { if (is_char(c))//是字符 one[j].push(c); else if (is_number(c))//是數字 { int x = i;// while (is_number(c)) { sconed.push_back(c); if (is_number(c = original[x++]))//是數值,則數組往後移動一位(確保下一步能讀取字符) i++; } sconed.push_back(#);//分隔符 if (!one[j].empty())//判斷是否為空 if (one[j].top() == * || one[j].top() == /)//高階運算,直接取出,壓入數值鏈表 { sconed.push_back(one[j].top()); one[j].pop(); } } else if (c == )) { Dum(j);//多余的運算符賦值 j--;//回到上一層的字符棧 } else j++;//新的字符棧 } Dum(j); } void Dum(int j)//多余的運算符逐個壓入數值鏈表 { while (!one[j].empty()) { sconed.push_back(one[j].top()); one[j].pop(); } }
View Code

2逆波蘭求值。

技術分享
void Do_it(std::stack<int> &mc)
{
    while (!sconed.empty())//不為空時。
    {
        char mid = sconed.front();//臨時存儲字符
        sconed.pop_front();//壓出
        switch (mid)//判斷
        {
            int a, b;
        case-:
            b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前兩個數值進行減法運算。
            mc.push(a - b);
            break;
        case+:
            b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前兩個數值進行加法運算。
            mc.push(a + b);
            break;
        case*:
            b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前兩個數值進行乘法運算。
            mc.push(a * b);
            break;
        case/:
            b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前兩個數值進行除法運算。
            if (b == 0)//分母不能位0
            {
                is_right = false;
                return;
            }
            else
                mc.push(a / b);
            break;
        default://獲得數值
        {
            int sum = 0;
            if (is_number(mid))
            {
                while (is_number(mid))
                {
                    sum = sum * 10 + mid - 0;//字符到數字的改變
                    mid = sconed.front();
                    if (is_number(mid))
                        sconed.pop_front();
                }
                mc.push(sum);
            }
        }
        }
    }
}
Do_it

3、GitHub源碼;

簡單計算機——逆波蘭表達式