中綴表達式轉化爲後綴表達式、後綴表達式求解(棧)

計算器我們都實現了很多了,但是,我們寫的計算器都是求解兩個操作數的,並不能求解一個表達式,如今棧已經學完了,那麼我們可不可以使用棧來實現表達式的求解呢?

我們數學上求解一個表達式是如何進行的,有括號的先求括號內部的,之後先算乘除,再算加減。現在如果來實現一個這樣可以求解表達式的計算器,怎樣進行呢?

首先是將中綴表達式轉化爲後綴表達式,具體的規則如下:

1、遇到操作數,直接輸出;
2、棧爲空時,遇到運算符,入棧;
3、遇到左括號,將其入棧;
4、遇到右括號,執行出棧操作,並將出棧的元素輸出,直到彈出棧的是左括號,左括號不輸出;
5、遇到其他運算符’+”-”*”/’時,彈出所有優先級大於或等於該運算符的棧頂元素,然後將該運算符入棧;
6、最終將棧中的元素依次出棧,輸出。

之後就是後綴表達式的求解了,大致是這樣的:

掃描後綴表達式, 如果是數字,則讓其進棧; 若爲操作符,則從棧中取出兩個操作數,先取出的作爲右操作數,後取出的作爲左操作數,然後進行該操作符的運算,並使其結果入棧。 重複上述過程,直至表達式掃描完成。 最終棧中只留一個元素,就是表達式結果。

下面是具體的實現代碼:

#include<iostream>
using namespace std;

#include<assert.h>
#include<stack>

//獲取操作符的優先級
int GetPriority(char ch, int flag)//flag爲1時表示棧內優先級  flag爲0表示棧外優先級
{
    if (ch == '+' || ch == '-')
    {
        if (flag)
        {
            return 3;
        }
        else
        {
            return 2;
        }
    }
    else if (ch == '*' || ch == '/' || ch == '%')
    {
        if (flag)
        {
            return 5;
        }
        else
        {
            return 4;
        }
    }
    else if (ch == '(')
    {
        if (flag)
        {
            return 1;
        }
        else
        {
            return 6;
        }       
    }
    else if (ch == ')')
    {
        if (flag)
        {
            return 6;
        }
        else
        {
            return 1;
        }
    }
}

//中綴表達式轉化後綴表達式
void InfixToPostfix(char *dest, char*src)
{
    assert(dest);
    assert(src);

    stack<char> s;//保存操作符,使其按照優先級從大到小輸出
    char* _cur = src;//用一個指針指向中綴表達式
    char* _temp = dest;//用指針指向存儲後綴表達式的空間

    while (*_cur != '\0')
    {
        if (*_cur >= '0' && *_cur <= '9')//如果是數字字符,那麼保存
        {
            *_temp++ = *_cur;
            _cur++;
            continue;
        }

        //如果是操作符,那麼分情況討論
        else if (*_cur == '+' ||* _cur == '-' || *_cur == '*' || *_cur == '/' || *_cur == '%' || *_cur == '(' || *_cur == ')')
        {
            if (s.empty())//
            {
                s.push(*_cur);
                _cur++;
            }
            else
            {
                if (*_cur == ')')
                {
                    while (s.top() != '(')
                    {
                        *_temp++ = s.top();
                        s.pop();
                    }
                    s.pop();//刪除棧頂的‘(’
                    *_cur++;
                }

                //如果當前操作符的優先級大於棧頂元素的優先級,將當前操作符入棧
                if (GetPriority(*_cur, 0) > GetPriority(s.top(), 1))
                {
                    s.push(*_cur);
                    _cur++;
                }
                else
                {
                    while (!s.empty() && GetPriority(*_cur, 0) < GetPriority(s.top(), 1))
                    {
                        *_temp++ = s.top();
                        s.pop();
                    }
                    s.push(*_cur);
                    _cur++;
                }
            }
        }
        else//跳過空格
        {
            *_temp++ = *_cur++;
        }
    }

    //將棧內剩餘元素放入表達式
    while (!s.empty())
    {
        *_temp++ = s.top();
        s.pop();
    }
}

//後綴表達式求值(計算器)
int Calculate(char *_postfix,char*_infix)
{
    InfixToPostfix(_postfix, _infix);

    stack<int> s;//注意前後兩個棧的使用用途不同,實例化也不同
    char*_cur = _postfix;
    int temp = 0;//保存數字字符轉化後的數字
    int res = 0;//保存運算結果

    while (*_cur != '\0')
    {
        if (*_cur >= '0'&&*_cur <= '9')
        {
            res = 0;
            while (!isspace(*_cur) && *_cur >= '0'&&*_cur <= '9')
            {
                temp = *_cur - '0';//將數字字符轉化爲數字
                res = res * 10 + temp;//  例如:12
                _cur++;
            }
            s.push(res);
        }
        else if (*_cur == '+' || *_cur == '-' || *_cur == '*' || *_cur == '/' || *_cur == '%')
        {
            int right = s.top();//先取出來的是右操作數
            s.pop();
            int left = s.top();
            s.pop();

            switch (*_cur)
            {
            case '+':
                s.push(left + right);
                break;
            case '-':
                s.push(left - right);
                break;
            case '*':
                s.push(left * right);
                break;
            case '/':
                if (right)
                {
                    s.push(left / right);
                    break;
                }
            case '%':
                s.push(left % right);
                break;
            }
            _cur++;
        }
        else//跳過空格
        {
            _cur++;
        }
    }
    if (!s.empty())
    {
        res = s.top();
        s.pop();
        return res;
    }
}

void FunTest()
{
    char* _infix = "12 * (3 + 4) - 6 + 8 / 2 ";
    char _postfix[20] = {};
    int result = Calculate(_postfix, _infix);
    cout <<result << endl;
}

int main()
{
    FunTest();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章