棧的應用——表達式求值


 

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

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

 

  表達式求值的代碼如下:

#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;
}

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM