棧的應用——表達式求值

 

  表達式求值是程序設計語言編譯中的一個基本問題,它的實現就是對「棧」的典型應用。本文針對表達式求值使用的是最簡單直觀的算法「算符優先法」。ios

  本文給出兩種方式來實現表達式求值,方式一直接利用中綴表達式求值,須要用到兩個棧,操做數棧和操做符棧。首先置操做數棧爲空棧, 操做符棧僅有「#」一個元素。依次讀入表達式中的每一個字符,如果操做數則進操做數棧,如果操做符則和操做符棧的棧頂運算符比較優先權做相應操做,直至整個表達式求值完畢。方式二首先把中綴表達式轉換爲後綴表達式並存儲起來,而後利用讀出的後綴表達式完成求值,其本質上是方式一的分解過程。git

 

  表達式求值的代碼以下:算法

#include <iostream>
#include "stack"
#include "map"
using namespace std;

/*   只能求一位整數的加減乘除混合運算   */

map<char, pair<int, int>> priority;    // 存放各個操做符的棧內棧外優先級,first是棧內,second是棧外
char infix[50];                        // 存放初始的中綴表達式
char postfix[50];                      // 存放轉化的後綴表達式
int result;

void MakePriority()        // 構造運算符優先級表
{
    priority.insert(make_pair('#', make_pair(0, 0)));    // isp(#)=0, icp(#)=0
    priority.insert(make_pair('\n', make_pair(0, 0)));   // isp(\n)=0, icp(\n)=0  表達式結尾的'#'用'\n'代替,這樣能夠省略表達式末尾的結束符'#'
    priority.insert(make_pair('(', make_pair(1, 6)));    // isp(()=1, icp(()=6
    priority.insert(make_pair('*', make_pair(5, 4)));    // isp(*)=5, icp(*)=4
    priority.insert(make_pair('/', make_pair(5, 4)));    // isp(/)=5, icp(/)=4
    priority.insert(make_pair('%', make_pair(5, 4)));    // isp(%)=5, icp(%)=4
    priority.insert(make_pair('+', make_pair(3, 2)));    // isp(+)=3, icp(+)=2
    priority.insert(make_pair('-', make_pair(3, 2)));    // isp(-)=3, icp(-)=2
    priority.insert(make_pair(')', make_pair(6, 1)));    // isp())=6, icp())=1
}

void InfixToPostfix()        // 把中綴表達式轉換爲後綴表達式
{
    int i = 0;
    stack<char> optrStack;   // 操做符棧
    char optr;               // optr爲棧頂的操做符
    optrStack.push('#');
    while (!optrStack.empty())
    {
        
        if (isdigit(infix[i]))  // 是操做數則直接輸出(追加到postfix結尾)
        {
            postfix[strlen(postfix)] = infix[i];
            postfix[strlen(postfix) + 1] = '\0';
            i++;                // 讀入中綴表達式的下一個字符
        }
        else                    // 是操做符, 比較優先級
        {
            optr = optrStack.top();    // 取出棧頂操做符
            if (priority[infix[i]].second > priority[optr].first)    // icp(infix[i]) > isp(optr),infix[i]入棧
            {
                optrStack.push(infix[i]);
                i++;
            }
            else if (priority[infix[i]].second < priority[optr].first)// icp(infix[i]) < isp(optr),optr退棧並輸出
            {
                postfix[strlen(postfix)] = optr;
                postfix[strlen(postfix) + 1] = '\0';
                optrStack.pop();
            }
            else        // icp(infix[i]) = isp(optr),退棧但不輸出,若退出的是'(',則繼續讀入下一個字符
            {
                optrStack.pop();
                if (optr == '(')
                    i++;
            }
        }
    }
}

void CalculateByPostfix()    // 經過後綴表達式求值
{
    int i = 0;
    stack<int> opndStack;    // 操做數棧
    int left, right;         // 左右操做數
    int value;               // 中間結果
    int newOpnd;
    while (postfix[i] != '#' && i < strlen(postfix))
    {
        switch (postfix[i])
        {
        case '+':
            right = opndStack.top();   // 從操做數棧中取出兩個操做數
            opndStack.pop();
            left = opndStack.top();
            opndStack.pop();
            value = left + right;
            opndStack.push(value);     // 中間結果入棧
            break;
        case '-':
            right = opndStack.top();
            opndStack.pop();
            left = opndStack.top();
            opndStack.pop();
            value = left - right;
            opndStack.push(value);
            break;
        case '*':
            right = opndStack.top();
            opndStack.pop();
            left = opndStack.top();
            opndStack.pop();
            value = left * right;
            opndStack.push(value);
            break;
        case '/':
            right = opndStack.top();
            opndStack.pop();
            left = opndStack.top();
            opndStack.pop();
            if (right == 0)
            {
                cerr << "Divide by 0!" << endl;
            }
            else
            {
                value = left / right;
                opndStack.push(value);
            }
            break;
        default:
            newOpnd = (int)(postfix[i] - 48);  // 操做數直接入棧
            opndStack.push(newOpnd);
            break;
        }
        i++;
    }
    result = opndStack.top();
}

void CalculateByInfix()        // 直接利用中綴表達式求值
{
    int i = 0;
    stack<char> optrStack;     // 操做符棧
    stack<int>    opndStack;   // 操做數棧
    char optr;                 // optr爲操做符棧頂的操做符
    int left, right, value;    // 左右操做數以及中間結果
    optrStack.push('#');
    optr = optrStack.top();
    while (!optrStack.empty())   // 直到操做符棧爲空
    {

        if (isdigit(infix[i]))   // 是操做數, 進操做數棧
        {
            value = (int)(infix[i] - 48);
            opndStack.push(value);
            i++;
        }
        else                         // 是操做符, 比較優先級
        {
            optr = optrStack.top();  // 取出操做符棧頂的操做符
            if (priority[infix[i]].second > priority[optr].first)      // icp(infix[i]) > isp(optr),infix[i]入棧
            {
                optrStack.push(infix[i]);
                i++;
            }
            else if (priority[infix[i]].second < priority[optr].first) // icp(infix[i]) < isp(optr),optr退棧並輸出
            {
                optrStack.pop();
                right = opndStack.top();    // 從操做數棧中取出兩個操做數
                opndStack.pop();
                left = opndStack.top();
                opndStack.pop();
                switch (optr)
                {
                case '+':
                    value = left + right;
                    opndStack.push(value);   // 中間結果入棧
                    break;
                case '-':
                    value = left - right;
                    opndStack.push(value);   // 中間結果入棧
                    break;
                case '*':
                    value = left * right;
                    opndStack.push(value);   // 中間結果入棧
                    break;
                case '/':
                    if (right == 0)
                    {
                        cerr << "Divide by 0!" << endl;
                    }
                    else
                    {
                        value = left / right;
                        opndStack.push(value);
                    }
                    break;
                default:
                    break;
                }
            }
            else
            {
                optrStack.pop();
                if (optr == '(')
                    i++;
            }
        }
    }
    result = opndStack.top();
}


int main()
{
    MakePriority();    // 構造運算符優先級表

    cout << "請輸入中綴表達式:";
    cin >> infix;

    cout << "直接利用中綴表達式求值爲:";
    CalculateByInfix();
    cout << result << endl;

    cout << "轉化爲後綴表達式:";
    InfixToPostfix();
    for (int i = 0;i < strlen(postfix);i++)
    {
        cout << postfix[i];
    }
    cout << endl;

    cout << "利用後綴表達式求值爲:";
    CalculateByPostfix();
    cout << result << endl;

    return 0;
}

 

  爲了方便起見,本文只是簡單的設計了一個針對一位整數的四則運算進行求值的算法,對於處理多位整數的四則運算,須要對本文接受輸入的數據類型進行「升階」,把字符數組換成字符串數組,將一個整數的多位數字存入一個字符串進行處理。數組

相關文章
相關標籤/搜索