欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > 算法刷题笔记 表达式求值(C++实现)

算法刷题笔记 表达式求值(C++实现)

2024/11/30 6:37:39 来源:https://blog.csdn.net/hanmo22357/article/details/140123233  浏览:    关键词:算法刷题笔记 表达式求值(C++实现)

文章目录

    • 题目描述
    • 基本思路
    • 实现代码

题目描述

  • 给定一个表达式,其中运算符仅包含 +,-,*,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。
  • 注意
    • 数据保证给定的表达式合法。
    • 题目保证符号-只作为减号出现,不会作为负号出现,例如,-1+2,(2+2)*(-(1+1)+2) 之类表达式均不会出现。
    • 题目保证表达式中所有数字均为正整数。
    • 题目保证表达式在中间计算过程以及结果中,均不超过2^31−1
    • 题目中的整除是指向0取整,也就是说对于大于0的结果向下取整,例如5/3=1,对于小于0的结果向上取整,例如5/(1−4)=−1。C++和Java中的整除默认是向零取整;Python中的整除//默认向下取整,因此Python的eval()函数中的整除也是向下取整,在本题中不能直接使用。

输入格式

  • 共一行,为给定表达式。

输出格式

  • 共一行,为表达式的结果。

数据范围

  • 表达式的长度不超过10^5

基本思路

  • 这道题是一道经典的算法模板题,即中缀算术表达式求值。这一类模板题中,所采用的运算符基本上都是二元运算符,需要借助的数据结构是栈,利用该数据结构先进后出的特性。
  • 首先,我们分析一下中缀表达式求值的难点是什么,可以发现该问题的难点在于一个算术表达式中,具有不同类型的运算符,有时候甚至带有括号,使得先进行什么运算,然后进行什么运算变得困难,因此该问题的核心就是确定表达式中各个运算的相对顺序。
  • 本题中之所以采用栈这种数据结构,是因为栈中元素的出栈顺序即可表示表达式中各个运算符之间的运算顺序;另外,用一个栈存储运算数,可以记录不同运算数之间参与运算的先后顺序。

实现代码

#include <iostream>       // 使用C++中的cin和cout进行输入输出更加简单
#include <cctype>         // 使用isdigit函数需要导入的头文件
#include <stack>          // 使用STL中自带的栈需要导入的头文件
#include <unordered_map>  // 使用STL中自带的哈希表(字典)需要导入的头文件
using namespace std;stack<int> numbers;     // 运算优先级越高的数字,越靠近栈顶
stack<char> operators;  // 运算优先级越高的运算,越靠近栈顶
// 以哈希表(相当于Python中的字典)的形式记录不同运算符的优先级(如果有更多的运算符则修改此表即可)
unordered_map<char, int> priority{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};void get_value(void)
{int number2 = numbers.top(); numbers.pop();int number1 = numbers.top(); numbers.pop();char operation = operators.top(); operators.pop();switch(operation){case '+' : numbers.push(number1 + number2);break;case '-' : numbers.push(number1 - number2);break;case '*' : numbers.push(number1 * number2);break;case '/' : numbers.push(number1 / number2);break;}
}int main(void)
{// 以C++字符串的形式输入中缀算术表达式string expression;cin >> expression;// 遍历整个字符串,确保表达式中的所有运算和数字都存入了栈for(int i = 0; i < expression.length(); ++ i){// 情况1:读入的字符是数字(使用cctype头文件中的isdigit函数判定),则将其与运算符分开if(isdigit(expression[i])){// 数字可能是多位整数,因此需要循环判定下一个字符是否也是数字int number = 0;// 使用条件表达式的短路规则进行判定,即表达式没有遍历完,且当前字符为数字while(i < expression.length() && isdigit(expression[i])){// 记录当前的数字的值并自增位置number = number * 10 + (expression[i] - '0');++ i;}// 将每一个运算数都压入运算数栈并更新位置numbers.push(number);-- i;}// 情况2:读入的字符是左括号,则直接将其入栈即可而无需判定else if(expression[i] == '(') operators.push('(');// 情况3:读入的字符是右括号,由于括号内优先级高,因此先计算括号内的else if(expression[i] == ')') {// 持续进行运算,直到找到该右括号对应的左括号,并将左括号出栈while(operators.top() != '(') get_value();operators.pop();}// 情况4:读入的字符是二元运算符(加减乘除)else {// 当运算符栈不为空,且当前遍历到的运算符的优先级不高于栈顶的元素的优先级,则先取出栈顶的元素进行计算while(!operators.empty() && priority[expression[i]] <= priority[operators.top()]) get_value();// 运算完成后将当前遍历到的运算符入栈operators.push(expression[i]);}}// 遍历完了表达式,运算过程可能仍然没有结束,需要继续运算直到运算符栈为空while(!operators.empty()) get_value();// 输出运算数栈的栈顶元素cout << numbers.top();return 0;
}
  • isdigit函数:用于判定一个字符是否是数字字符(0-9),使用时需要导入头文件<cctype>
  • 短路原则:在使用&&连接的表示“与”的条件表达式中,只有前一个条件表达式为真,才会继续判定下一个条件表达式,因此在代码情况1中的while语句,并不会出现expression[i]越界的问题。
  • 栈的操作:C++的STL中提供了栈模板类,使用时需要首先导入头文件<stack>。可以使用栈对象的top()函数获取栈顶元素,使用pop()函数弹出栈顶元素(无返回值),使用empty()函数判定栈是否为空(返回布尔值),使用push()函数入栈一个元素。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com