实验一 线性结构编程题1. 表达式求值

本文介绍了一个程序,用于处理包含#结尾的算术表达式,检查非法字符,将其转换为后缀表达式,并利用STL库进行计算。程序通过栈操作实现中缀表达式到后缀表达式的转换和求值。
摘要由CSDN通过智能技术生成

【问题描述

设计一个程序,对输入的以#为结束的算术表达式(包括+,-,*,/,(,) ),首先判断表达式是否含有非法字符(即非+,-,*,/, (,) 之外的字符),

如果含有非法字符,则报错误信息;

如果正确,计算并输出这个表示式的值。

本题希望利用算符优先关系,实现对算术四则混合运算表达式的求值。

输入格式

以#为结束符的算术表达式。

输出格式

  对于每组测试数据算术表达式,如果含有非法字符,输出“NO”,否则输出表达式的值,行尾不得有多余的空格。 

要求:

使用STL求解表达式的值 

样例输入

3+4*(5-3)# 

样例输出

   11 

样例说明

  输入样例是合法的表达式,因此求表达式的值,并输出11。 

样例输入

3+;4*(5-3)#

样例输出

表达式不合法 

样例说明

输入样例含不合法的字符';',因此输出“NO”。

【特别说明

建议使用STL

【思路分析】

这种表达式称为中缀表达式,做法有二,1:可以开辟两个栈直接解决,2:先把中缀表达式转化成后缀表达式再进行求解。本题采用的做法为2。

转化成后缀表达式规则:

       1.设定运算符栈;
  2.从左到右遍历中缀表达式的每个数字和运算符;
  3.若当前字符是数字,则直接输出成为后缀表达式的一部分;
  4.若当前字符为运算符,则判断其与栈顶运算符的优先级,若优先级大于栈顶运算符,则进栈;若优先级小于等于栈顶运算符,退出栈顶运算符成为后缀表达式的一部分,然后将当前运算符放入栈中;
  5.若当前字符为“(”,进栈;
  6.若当前字符为“)”,则从栈顶起,依次将栈中运算符出栈成为后缀表达式的一部分,直到碰到“(”。将栈中“(”出栈,不需要成为后缀表达式的一部分,然后继续扫描表达式直到最终输出后缀表达式为止。

注意本题中表达式中的数字并不是一位数,需要用cin读取。转化成后缀表达式时不能用string接收,需要用vector进行隔断。本题做法并不是最佳,仅作参考。

#include<vector>
#include<algorithm>
#include<iostream>
#include <stack>
#include <sstream>

using namespace std;

int calculate(const string &s) {
    stringstream ss(s);
    stack<char> opers;
    stack<int> nums;
    int x;
    char oper;
    vector<string> regex;
    for (int i = 0; i < s.size(); i++) {
        //由于stringstream一次性输入数字和符号,符号后可能紧跟着'(',需要特判
        if (s[i]=='#'){
            break;
        } else if (s[i] > '0' && s[i] < '9') {
            ss >> x >> oper;
            regex.push_back(to_string(x));
        } else {
            ss >> oper;
            goto flag;
        }
        while (x /= 10)i++;
        i++;//计数,i为当前字符串下标
        flag:
        if (opers.empty()) {
            opers.push(oper);
        } else if (oper == '(') {
            opers.push(oper);
        } else if (oper == ')') {
            while (opers.top() != '(') {
                string tmp;
                tmp.push_back(opers.top());
                regex.push_back(tmp);
                opers.pop();
            }
            opers.pop();
        } else if ((oper == '-' || oper == '+') && !opers.empty() && opers.top() != '(') {
            while (!opers.empty()) {
                string tmp;
                tmp.push_back(opers.top());
                regex.push_back(tmp);
                opers.pop();
            }
            opers.push(oper);
        } else if (!opers.empty() && opers.top() == '(') {
            opers.push(oper);
        } else if (oper == '*' || oper == '/') {
            opers.push(oper);
        } else if (oper == '#') {
            break;
        }
    }
    while (!opers.empty()) {
        string tmp;
        tmp.push_back(opers.top());
        regex.push_back(tmp);
        opers.pop();
    }
    //此处进行后缀表达式的计算
    for (string i: regex) {
        if (i[0] > '9' || i[0] < '0') {
            int a = nums.top();
            nums.pop();
            int b = nums.top();
            nums.pop();
            switch (i[0]) {
                case '+':
                    nums.push(a + b);
                    break;
                case '-':
                    nums.push(b - a);
                    break;
                case '*':
                    nums.push(a * b);
                    break;
                case '/':
                    nums.push(b / a);
                    break;
            }
        } else {
            ss.str(string());
            ss.clear();//清空ss,不需要创建新的stringstream对象
            ss << i;
            int tmp;
            ss >> tmp;
            nums.push(tmp);
        }
    }
    return nums.top();
}

int main() {
    string s;
    cin >> s;
    for (int i = 0; i < s.size(); i++) {
        if ((s[i] != '+' && s[i] != '-' && s[i] != '(' && s[i] != ')' && s[i] != '/' && s[i] != '*' && s[i] != '#') &&
            (s[i] < '0' ||
             s[i] > '9')) {
            cout << "NO";
            return 0;
        }
    }
    cout << calculate(s) << endl;
}
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值