1. 程式人生 > >c++利用棧簡單實現四則中綴表示式轉字尾表示式,並算值。

c++利用棧簡單實現四則中綴表示式轉字尾表示式,並算值。

      最近在學習資料結構與演算法,學到棧這裡,就基於棧實現了一個簡答四則表示式算值的程式。平時我們寫的那
種表示式就是中綴,而計算機處理中綴是不佔優勢的一般都是將中綴轉成字尾再計算值,在這裡我也利用這個思路,
將中綴表示式分為以下兩部:
     A.中綴表示式轉成字尾表示式,主要有以下幾步:
      a.初始化一個運算子棧
      b.從左到右讀取一個字元
      c.如果是運算元就直接輸出到字尾表示式
      d.如果是左括號就壓入操作符棧
       e.如果是右括號,則把與之匹配的左括號之間的運算子全部輸出
       f.如果是運算子就分情況執行以下操作
1).如果棧為空就直接壓入
2).如果棧中有運算子,切當前運算子比棧頂運算子優先順序高就壓入,否則就彈出棧頂運算子 ,並一直重複1)2)直到棧頂運算子優先順序低於待處理運算子或棧為空 3).重複b
直到讀取完畢 B.字尾表示式求值,這個就相對簡單一些了: a.初始化一個運算元棧 b.依次讀取字尾表示式,遇到運算數就壓進運算數棧,遇到操作符就將棧頂兩個數pop出來求值 然後push進棧。一直迴圈執行b知道字尾表示式讀取完畢,最後運算元棧頂那個數就是表示式。
下面就直接貼程式碼了,程式碼註釋基本能夠幫助快速讀懂程式。
#include <iostream>
#include <stack>
using namespace std;

int getPriority(char c);    //輸入運算子返回優先順序
bool isLeft(char c);        //判斷是否是左括號
bool isRight(char c);       //判斷是否是右括號
bool isOperator(char c);    //判斷是否是操作符(+-*/)
bool isNumber(char c);      //判斷是否是數字
double calculate(string postfix);   //傳入字尾表示式,計算值
string convertToPostfix(const string& expression); //將中綴表示式轉化為字尾表示式

int main() {

    stack<char> operatorStack;
    string expression,postfix;
    cout << "請輸入要計算的表示式:"<<endl;

    getline(cin,expression);
    postfix = convertToPostfix(expression);

    //輸出結果
    cout << "字尾表示式為(數字之間以#號分割)->"<<postfix << endl;
    if (expression.at(expression.length()-1) == '=')
        cout <<expression<<calculate(postfix)<<endl;
    else
        cout <<expression<<"="<<calculate(postfix)<<endl;
}

string convertToPostfix(const string& expression){
    stack<char> operatorStack;
    string postfix;
    //依次讀取輸入的字元並按字元型別分別處理
    for(int current = 0; current < expression.length(); current++){
        char c = expression.at(current);
        if(!isNumber(c) && !isOperator(c) && c !='(' && c != ')'){
            cout << "請輸入正確表示式!" << endl;
            exit(0);
        }
        if(c != ' ' && c != '='){
            //如果是左括號就壓棧
            if(isLeft(c)) {
                operatorStack.push(c);
            } else if (isRight(c)){     //是右括號則將和左括號之間的pop出去拼接到字尾表示式
                while(!operatorStack.empty() && operatorStack.top() != '('){
                    postfix.append(1,operatorStack.top());
                    operatorStack.pop();
                }
                operatorStack.pop();        //最後將左括號pop
            } else if(isOperator(c)){   //如果是操作符
                if(current+1 < expression.length()){
                    if (isOperator(expression.at(current+1))) {
                        cout << "請輸入正確的表示式";
                        exit(0);
                    }
                }
                if(current-1 >= 0){
                    if(isOperator(expression.at(current-1))){
                        cout << "請輸入正確的表示式";
                        exit(0);
                    }
                }
                if(operatorStack.empty()){  //如果操作符棧為空就直接壓棧
                    operatorStack.push(c);
                } else{                     //否則就將棧頂優先順序低的依次出棧,直到棧為空或者,棧頂運算子優先順序低於當前運算子
                    while(getPriority(c) <= getPriority(operatorStack.top())){
                        postfix.append(1,operatorStack.top());
                        operatorStack.pop();
                        if(operatorStack.empty())
                            break;
                    }
                    operatorStack.push(c);
                }
            } else {    //最後如果是數字的話就直接接到字尾表示式
                postfix.append(1,c);            //同時為了方便後面計算字尾表示式值的時候明確多位數的起止,特在每個整數後面加一個分隔符$
                if(current+1 < expression.length()){
                    if (!isNumber(expression.at(current+1))){
                        postfix.append(1,'#');//數字分隔符
                    }
                }
            }
        }
    }
    //中綴表示式讀取完畢後將運算子棧中剩下的運算子拼接到字尾表示式中
    while(!operatorStack.empty()){
        if(operatorStack.top() == '(' || operatorStack.top() == ')'){
            cout << "左右括號不匹配,表示式錯誤!";
            exit(0);
        }
        postfix.append(1,operatorStack.top());
        operatorStack.pop();
    }
    return postfix;
}
//返回運算子優先順序
int getPriority(char c){
    if(c == '*' || c == '/')
        return 2;
    else if(c == '+' || c == '-')
        return 1;
    else
        return  0;
}

bool isRight(char c){
    if(c == ')')
        return true;
    else
        return false;
}

bool isLeft(char c){
    if(c == '(')
        return true;
    else
        return false;
}

bool isOperator(char c){
    if(c == '*' || c == '/' || c == '+' ||c == '-')
        return true;
    else
        return false;
}

double calculate(string postfix){
    stack<double> result;
    char c;
    for (int i = 0; i < postfix.length();i++) {
        c = postfix.at(i);
        if (isOperator(c)) {
            double a = result.top();
            result.pop();
            double b = result.top();
            result.pop();
            double temp;
            switch (c) {
                case '+' :
                    temp = b + a;
                    break;
                case '-' :
                    temp = b - a;
                    break;
                case '/' :
                    if(a == 0){
                        cout << "除零錯誤!";
                        exit(0);
                    }
                    temp = b / a;
                    break;
                case '*' :
                    temp = b * a;
                default:
                    break;
            }
            result.push(temp);
        } else if(isNumber(c)){
            double num = c - '0';
            while(isNumber(postfix.at(i+1))){
                num = num*10+ (postfix.at(i+1) - '0');
                i++;
            }
            result.push(num);
        }
    }
    return result.top();
}

bool isNumber(char c){
    if(c>='0'&& c<='9')
        return true;
    else
        return false;
}
當然程式碼中加入了一些判別表示式錯誤的片段,比如左右括號不匹配,或是除數為零,以及為了支援多位數,特意在每個
數結束處加一個#號方便字尾表示式計算值時識別,相關程式碼段如下:
            postfix.append(1,c); //同時為了方便後面計算字尾表示式值的時候明確多位數的起止,特在每個整數後面加一個分隔符#                if(current+1 < expression.length()){
                    if (!isNumber(expression.at(current+1))){
                        postfix.append(1,'#');//數字分隔符
                    }
                }




#