アルゴリズム 10 - C++ は中置式の計算を実装します

タイトル説明:
  +、-、x、/ のみを含む負でない整数の計算式を読み込み、式の値を計算します

入力形式:
  テスト入力には複数のテスト ケースが含まれており、各テスト ケースは 1 行を占め、各行は 200 文字を超えず、整数と演算子はスペースで区切られます。違法な表現はありません。行内に 0 だけがある場合は入力が終了し、対応する結果を出力する必要はありません。

出力形式:
  テスト ケースごとに 1 行、つまり式の値を小数点第 2 位まで正確に出力します。

入力例:

30/90-26+97-5-6-13/88*6+51/29+79*87+57*92
0

出力例:

12178.21

アイデア:

  • 中置式から後置式へ
  • 後置式を評価する

中置式から後置式へ:

  • 演算子を一時的に保存するために演算子スタックを設定する; 後置式を保存するために配列またはキューを設定する
  • 中置式を左から右にスキャンし、オペランドが見つかった場合 (注: オペランドは複数の場合があります)、そのオペランドを中置式に追加します。
  • 演算子 op が見つかった場合、op はスタック上の最上位の演算子の優先順位と比較されます。op の優先順位がスタックの最上位にある演算子の優先順位より高い場合、op は演算子スタックにプッシュされます。そうでない場合、演算子スタックは演算子をポップし、後置式に追加し続けます。演算の優先順位がスタックの最上位の演算よりも高い場合、演算子の優先順位が決まり、最上位の演算子を演算子スタックにプッシュします。
  • インフィックス式がスキャンされるまで上記の操作を繰り返します。演算子スタックにまだ要素がある場合は、それらをポップアップして、順番にサフィックス式に追加します。

後置式を評価します。

  接尾辞式を左から右にスキャンし、それがオペランドの場合はスタックにプッシュされ、演算子の場合はオペランドが連続的にポップされます (2 番目のオペランドが最初にポップされ、最初のオペランドが後でポップされます) )、その後、演算子の演算を実行し、新しいオペランドを生成してスタックにプッシュします。後置式がスキャンされるまで、これはスタック上にのみ存在する最後の結果になります。

コード:

#include<iostream>
#include<cstdio>
#include<string>
#include<stack>
#include<queue>
#include<map>
using namespace std;

struct node{
    double num;//操作数
    char op;//操作符
    bool flag;//true表示操作数,false表示操作符
};

string str;
stack<node> s;//操作符栈
queue<node> q;//后缀表达式序列
map<char,int> op;

void Change(){//中缀表达式转后缀表达式
    double num;
    node temp;
    for(int i = 0 ; i < str.length();){
        if(str[i]>='0'&&str[i]<='9'){
            //如果是数字
            temp.flag = true;
            temp.num = str[i++]-'0';
            while(i<str.length()&&str[i]>='0'&&str[i]<='9'){
                //后面一位还是数字,说明这个数还没取完
                temp.num = temp.num*10+(str[i]-'0');
                i++;
            }
            q.push(temp);//加入后缀表达式序列
        }else{
            //如果是操作符
            temp.flag = false;
            //只要操作符栈的栈顶元素比该操作符优先级高
            //就把操作符栈栈顶元素弹出加入到后缀表达式
            while(!s.empty()&&op[str[i]]<=op[s.top().op]){
                q.push(s.top());
                s.pop();
            }
            temp.op = str[i];
            s.push(temp);
            i++;
        }
    }
    //如果操作符栈中还有操作符,就将它弹出加入后缀表达式
    while(!s.empty()){
        q.push(s.top());
        s.pop();
    }
}

 double Cal(){
        //计算后缀表达式
        double temp1,temp2;
        node cur,temp;
        while(!q.empty()){
            cur = q.front();//记录队首元素
            q.pop();
            if(cur.flag==true){
                //如果是操作数,直接压入栈
                s.push(cur);
            }else{
                temp2 = s.top().num;//第二个操作数
                s.pop();
                temp1 = s.top().num;//第一个操作数
                s.pop();
                temp.flag = true;//标记临时操作数
                if(cur.op == '+')
                    temp.num = temp1+temp2;
                else if(cur.op == '-')
                    temp.num = temp1 - temp2;
                else if(cur.op == '*')
                    temp.num = temp1 * temp2;
                else
                    temp.num = temp1 / temp2;
                s.push(temp);
            }
        }
        return s.top().num;
}

int main(){
    op['+'] = op['-'] = 1;
    op['*'] = op['/'] = 2;
    while(getline(cin,str),str!="0"){
        for(string::iterator it = str.end();it!=str.begin();it--){
            if(*it == ' ')
                str.erase(it);//把表达式中的空格删除
        }
        while(!s.empty())
            s.pop();//初始化栈
        Change();
        printf("%.2f\n",Cal());
    }
    return 0;
}

おすすめ

転載: blog.csdn.net/weixin_46025531/article/details/122808963