交互式表达式求值(支持多种类型的运算符)

2023-11-02 05:10

本文主要是介绍交互式表达式求值(支持多种类型的运算符),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

交互式表达式求值(支持多种类型的运算符)

一、说明

  1. 输入字符串为中缀表达式,无需转为后缀表达式

  2. 支持的运算符包括:

算术运算符:“+,-,*,/”

关系运算符:“>,<,>=,<=,=,!=”(注意等于运算符采用的是一个等号)

逻辑运算符:“&&,||”

单目运算符:“++,–”

  1. 支持大于10的数字,不支持负数操作数,但支持中间结果和返回值为负数
  2. 支持逗号分隔表达式
  3. 支持变量,程序运行期间,变量保持其值
  4. 以交互方式求值,按行输入表达式,回车显示其值

二、算法原理&步骤

本文算法对中缀表达式形式字符串进行求值,同时支持与或运算和逻辑运算(若含有关系运算符或者逻辑运算符,则输出为1或者0)。类似于加减乘除,将关系运算符和逻辑运算符看作优先级低的运算符进行处理,优先级:单目运算符>算术运算符>关系运算符>逻辑运算符。

步骤:

  1. 初始化两个空堆栈,一个存放操作数,一个存放运算符。
  2. 初始化一个Map,用于存储运行过程中的变量。
  3. 找到表达式中 '=‘和’,‘的位置,‘,’会被视为两个完整语句,‘=’会将左边和右边的分隔开来,’='左边作为待赋值的变量,‘=’右边视为待求值的表达式。
  4. . 对于每个表达式,从左至右扫描输入字符串,依次读取。
  • 4.1 若为操作数,则压入操作数栈;
  • 4.2 若为字母开头,则继续扫描,到下一个字母为操作符为止,都被视为变量,在Map中查找该变量的值,压入操作数栈。
  • 4.2 若为运算符,判断其优先级是否大于运算符栈栈顶元素优先级。若大于栈顶元素优先级,则直接压栈;否则,弹出栈顶元素operator,同时依次从操作数栈中弹出两个元素number1,number2,计算表达式(number2 operator number1)的值value,并将值value压入操作数栈。重复上述过程直至当前扫描的操作符优先级大于栈顶元素,然后将当前运算符压栈。
  1. 弹出运算符栈顶元素operator,判断是单目运算符还是双目运算符,单目运算符则弹出一个操作数,否则同时依次从操作数栈中弹出两个元素number1,number2,计算表达式(number2 operator number1)的值value,并将值value压入操作数栈。重复上述过程直至运算符栈为空。

  2. 此时操作数栈应该只有一个元素,即为表达式的值。

三、代码

#include <bits/stdc++.h>
using namespace std;
unordered_map<string,int> Map;/* 判断字符是否属于运算符 */
bool isOperator(char c)
{switch (c){case '-':case '+':case '*':case '/':case '%':case '<':case '>':case '=':case '!':case '&':case '|':return true;default:return false;}
}/* 获取运算符优先级 */
int getPriority(string op)
{int temp = -1;if (op == "++" || op == "--")temp = 5;else if (op == "*" || op == "/" || op == "%")temp = 4;else if (op == "+" || op == "-")temp = 3;else if (op == ">" || op == "<" || op == ">=" || op == "<="|| op == "=" || op == "!=")temp = 2;else if (op == "&&" || op == "||")temp = 1;return temp;
}
/** 返回一个两元中缀表达式的值* syntax: num_front op num_back* @param num_front: 前操作数* @param num_back: 后操作数* @param op: 运算符*/
int Calculate(int num_front, int num_back, string op)
{if (op == "+")return num_front + num_back;else if (op == "-")return num_front - num_back;else if (op == "*")return num_front * num_back;else if (op == "/")return num_front / num_back;else if (op == "%")return num_front % num_back;else if (op == "!=")return num_front != num_back;else if (op == ">=")return num_front >= num_back;else if (op == "<=")return num_front <= num_back;else if (op == "==")return num_front == num_back;else if (op == ">")return num_front > num_back;else if (op == "<")return num_front < num_back;else if (op == "&&")return num_front && num_back;else if (op == "||")return num_front || num_back;else if (op == "++")return num_front + 1;else if (op == "--")return num_front - 1;return 0;
}
/* 新运算符入栈操作 */
void addNewOperator(string new_op, stack<int>& operand_stack, stack<string>& operator_stack)
{while (!operator_stack.empty() && getPriority(operator_stack.top()) >= getPriority(new_op)){int num2 = operand_stack.top();operand_stack.pop();int num1 = operand_stack.top();operand_stack.pop();string op = operator_stack.top();operator_stack.pop();int val = Calculate(num1, num2, op);operand_stack.push(val);}operator_stack.push(new_op);
}int equalpos(string input)
{for (int i=1;i<input.size()-1;i++){if(input[i]=='=' && !isOperator(input[i-1]) && !isOperator(input[i+1])){return i;}}return -1;
}/* 字符串表达式求值* @param input: 输入的字符串* @param output: 表达式的值,若含有关系运算符则为1或者0* return 计算过程是否正常*/
bool ExpValue(string input_prev,int& output)
{int equal_pos = equalpos(input_prev);string input = "";string var = "";if(equal_pos==-1) input = input_prev;else {var = input_prev.substr(0,equal_pos);input = input_prev.substr(equal_pos+1,input_prev.size());}stack<int> operand_stack;stack<string> operator_stack;char prev = 0; // 上一个属于运算符的字符for (int i = 0; i < input.size(); i++){char c = input[i];// prev是否是一个完整运算符if (!isOperator(c) && prev){string new_op = string("").append(1, prev);addNewOperator(new_op, operand_stack, operator_stack);prev = 0;}// 数字if (isdigit(c)){int val_c = c - '0';if (i > 0 && isdigit(input[i - 1])){int top_num = operand_stack.top();top_num = top_num * 10 + val_c;operand_stack.pop();operand_stack.push(top_num);}elseoperand_stack.push(val_c);}//变量else if(c>='a' && c<='z' || c>='A' && c<='Z'){string s = ""; s = s+c;c = input[++i];while(c>='a' && c<='z' || c>='A' && c<='Z' || c>='0' && c<='9' || c=='_'){s += c;c = input[++i];}if(Map.find(s)!=Map.end()){operand_stack.push(Map[s]);i--;}}// 运算符字符else if (isOperator(c)){// 处理两字符运算符if (prev){string new_op = string("").append(1, prev).append(1, c);addNewOperator(new_op, operand_stack, operator_stack);prev = 0;}elseprev = c;}else if (c == '(')operator_stack.push("(");else if (c == ')'){// 处理括号内的运算符while (operator_stack.top()!="("){int num1 = operand_stack.top();operand_stack.pop();int num2 = operand_stack.top();operand_stack.pop();string op = operator_stack.top();operator_stack.pop();int val = Calculate(num2, num1, op);operand_stack.push(val);}operator_stack.pop(); // 弹出"("}}
//    assert(operand_stack.size() == operator_stack.size() + 1);// 弹出所有运算符while(!operator_stack.empty()){string op = operator_stack.top();operator_stack.pop();int num1,num2;if(op=="++" || op=="--"){  //单目运算符num1 = operand_stack.top();operand_stack.pop();num2 = 0;}else{num2 = operand_stack.top();operand_stack.pop();num1 = operand_stack.top();operand_stack.pop();}int val = Calculate(num1, num2, op);
//        cout<<num1<<op<<num2<<"="<<val<<endl;operand_stack.push(val);}if (operand_stack.size() == 1) {output = operand_stack.top();if(var!="")Map[var] = output;return true;}return false;
}vector<string> split(string s, char ch)
{vector<string> res;int n = s.size();int i = 0;while(i < n){int j = i + 1;while(j < n && s[j] != ch) ++j;res.push_back(s.substr(i, j - i));i = j + 1;}return res;
}void test()
{string s0 = "10-1*10+3%2";string s1 = "100 + (3-33)*2";string s2 = "20+1 >= 20 && 20+1 < 20";string s3 = "10>20 || 10/1>=5";string s4 = "a4=2";string s5 = "b=a4+3";string s6 = "b++";int ret = -1;if (ExpValue(s0, ret))cout << s0 << ": " << ret << endl;if (ExpValue(s1, ret))cout << s1 << ": " << ret << endl;if (ExpValue(s2, ret))cout << s2 << ": " << ret << endl;if (ExpValue(s3, ret))cout << s3 << ": " << ret << endl;if (ExpValue(s4, ret))cout << s4 << ": " << ret << endl;if (ExpValue(s5, ret))cout << s5 << ": " << ret << endl;if (ExpValue(s6, ret))cout << s6 << ": " << ret << endl;
}void Interactive_Calculator()
{while(true){char *s;int ret = -1;cout<<"&";  cin>>s;vector<string> exprs = split(s,',');for(int i=0;i<exprs.size();i++){ExpValue(exprs[i],ret);}cout<<ret<<endl;
//        if (ExpValue(s, ret))
//            cout << ret << endl;}
}int main()
{
//    test();Interactive_Calculator();return 0;
}

四、测试结果

image-20220918112217717

image-20220918112224791

这篇关于交互式表达式求值(支持多种类型的运算符)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/328342

相关文章

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

Python 交互式可视化的利器Bokeh的使用

《Python交互式可视化的利器Bokeh的使用》Bokeh是一个专注于Web端交互式数据可视化的Python库,本文主要介绍了Python交互式可视化的利器Bokeh的使用,具有一定的参考价值,感... 目录1. Bokeh 简介1.1 为什么选择 Bokeh1.2 安装与环境配置2. Bokeh 基础2

Java中的Lambda表达式及其应用小结

《Java中的Lambda表达式及其应用小结》Java中的Lambda表达式是一项极具创新性的特性,它使得Java代码更加简洁和高效,尤其是在集合操作和并行处理方面,:本文主要介绍Java中的La... 目录前言1. 什么是Lambda表达式?2. Lambda表达式的基本语法例子1:最简单的Lambda表

Spring Boot 集成 Quartz并使用Cron 表达式实现定时任务

《SpringBoot集成Quartz并使用Cron表达式实现定时任务》本篇文章介绍了如何在SpringBoot中集成Quartz进行定时任务调度,并通过Cron表达式控制任务... 目录前言1. 添加 Quartz 依赖2. 创建 Quartz 任务3. 配置 Quartz 任务调度4. 启动 Sprin

SpringShell命令行之交互式Shell应用开发方式

《SpringShell命令行之交互式Shell应用开发方式》本文将深入探讨SpringShell的核心特性、实现方式及应用场景,帮助开发者掌握这一强大工具,具有很好的参考价值,希望对大家有所帮助,如... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

SpringBoot @Scheduled Cron表达式使用方式

《SpringBoot@ScheduledCron表达式使用方式》:本文主要介绍SpringBoot@ScheduledCron表达式使用方式,具有很好的参考价值,希望对大家有所帮助,如有... 目录Cron 表达式详解1. 表达式格式‌2. 特殊字符解析3. 常用示例‌4. 重点规则5. 动态与复杂场景‌

Spring Boot 集成 Quartz 使用Cron 表达式实现定时任务

《SpringBoot集成Quartz使用Cron表达式实现定时任务》本文介绍了如何在SpringBoot项目中集成Quartz并使用Cron表达式进行任务调度,通过添加Quartz依赖、创... 目录前言1. 添加 Quartz 依赖2. 创建 Quartz 任务3. 配置 Quartz 任务调度4. 启