C++的STL 栈 实现四则运算
使用栈实现四则运算,支持+,-,*,/,(,)
输入为字符串,输出为计算好的数值,如不符合四则运算的规定,则异常退出
这个实现借用了栈以及字符处理状态机的思想:
- 维护两个栈:一个用于数值,另一个用于存放计算符号
- 字符状态机用于遍历输入的字符串过程中进行对应数值处理和计算符号处理的状态转换
在第一个思想中:符号栈中存在优先级,即*和/的优先级高于+和-,同时括号的优先级高于*和/,所以符号栈的入栈顺序以及触发计算时机需要在状态机转动的过程中谨慎处理。
入栈基本过程类似如下:
对于1+121的入栈过程如下
状态机的处理过程如下:
核心创建两个栈的算法如下(文末有完整测试代码):
int state_change(string s) {static const int BEGIN_STATE = 0;static const int NUM_STATE = 1;static const int OPE_STATE = 2;int STATE = BEGIN_STATE;map<char,int> prio;stack<int> num_stack;stack<char> oper_stack;int cacl_flag = -1;int number = 0;/*设置运算符优先级*/prio['+'] = 1;prio['-'] = 1;prio['*'] = 2;prio['/'] = 2;prio['('] = 3;int i;if (s.empty()) {print_erro("string is empty\n",__LINE__);}for(int i = 0;i < s.size(); ++i) {if (s[i] == ' ') {continue;}switch (STATE){case BEGIN_STATE: //初始状态if (s[i] >= '0' && s[i] <= '9') {STATE = NUM_STATE;} else if(s[i] == ')'){print_erro("string is not leagal\n",__LINE__);} else {STATE = OPE_STATE;}i--; //处理退格break;case NUM_STATE: //数字状态if (s[i] >= '0' && s[i] <= '9') {number = number*10 + s[i] - '0'; //将数值型字符串转换为数字} else {num_stack.push(number);if (cacl_flag == 2) { //优先计算*和/,+和-末尾计算calculate(num_stack,oper_stack);}STATE = OPE_STATE;number = 0;i--;}break;case OPE_STATE: //字符状态if(prio[s[i]] == 1) { //+,- 字符入栈,设置计算优先级oper_stack.push(s[i]);cacl_flag = 1;} else if(prio[s[i]] == 2) {//*,/ 字符入账,设置计算优先级oper_stack.push(s[i]);cacl_flag = 2;} else if (prio[s[i]] == 3) { // 如果为左括号,则切换状态到数字cacl_flag = 3;STATE = NUM_STATE;break;} else if (s[i] == ')') { //如果为右括号,则进行计算calculate(num_stack,oper_stack);break;} else if(s[i] >= '0' && s[i] <= '9') {STATE = NUM_STATE;i--; //如果为数字,则处理退格,并进行状态切换} else {print_erro("string is not leagal \n",__LINE__);}break;default:break;}}if (number != 0) { //处理最后的数字入栈num_stack.push(number);calculate(num_stack,oper_stack);}if (number == 0 && num_stack.empty()) { return 0;}while(!oper_stack.empty() && num_stack.size() != 1) { //处理数字栈和字符栈中的剩余数据calculate(num_stack,oper_stack);}if (!oper_stack.empty()) { //如果字符栈中还有字符,则为异常四则运算print_erro("string is not leagal", __LINE__);}return num_stack.top();
}
依据字符栈和数字栈进行计算的过程如下:
这里需要注意两个运算的取值上的顺序问题(从栈中取出来的数值和输入是相反的),减法需要进行取反操作,除法需要进行数值顺序反转操作
void calculate(stack<int> &num_stak, stack<char> &oper_stack) {int num1;int num2;int result;num1 = num_stak.top();num_stak.pop();num2 = num_stak.top();num_stak.pop();if (oper_stack.top() == '+') {result = num1 + num2;} else if (oper_stack.top() == '-') {result = -(num1 - num2); //减法取反} else if (oper_stack.top() == '*') {result = num1 * num2;} else if (oper_stack.top() == '/') {if (num1 == 0) {print_erro("divide num is 0 \n", __LINE__);}result = num2 / num1; //数值反转进行计算} else {print_erro("operator failed\n", __LINE__);}oper_stack.pop();num_stak.push(result);
}
完整代码如下:
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>using namespace std;void print_erro(string s,int line) {cout << s <<" " << line << endl;exit(-1);
}void calculate(stack<int> &num_stak, stack<char> &oper_stack) {int num1;int num2;int result;num1 = num_stak.top();num_stak.pop();num2 = num_stak.top();num_stak.pop();if (oper_stack.top() == '+') {result = num1 + num2;} else if (oper_stack.top() == '-') {result = -(num1 - num2);} else if (oper_stack.top() == '*') {result = num1 * num2;} else if (oper_stack.top() == '/') {if (num1 == 0) {print_erro("divide num is 0 \n", __LINE__);}result = num2 / num1;} else {print_erro("operator failed\n", __LINE__);}oper_stack.pop();num_stak.push(result);
}int state_change(string s) {static const int BEGIN_STATE = 0;static const int NUM_STATE = 1;static const int OPE_STATE = 2;int STATE = BEGIN_STATE;map<char,int> prio;stack<int> num_stack;stack<char> oper_stack;int cacl_flag = -1;int number = 0;prio['+'] = 1;prio['-'] = 1;prio['*'] = 2;prio['/'] = 2;prio['('] = 3;int i;if (s.empty()) {print_erro("string is empty\n",__LINE__);}for(int i = 0;i < s.size(); ++i) {if (s[i] == ' ') {continue;}switch (STATE){case BEGIN_STATE:if (s[i] >= '0' && s[i] <= '9') {STATE = NUM_STATE;} else if(s[i] == ')'){print_erro("string is not leagal\n",__LINE__);} else {STATE = OPE_STATE;}i--;break;case NUM_STATE:if (s[i] >= '0' && s[i] <= '9') {number = number*10 + s[i] - '0';} else {num_stack.push(number);if (cacl_flag == 2) {calculate(num_stack,oper_stack);}STATE = OPE_STATE;number = 0;i--;}break;case OPE_STATE:if(prio[s[i]] == 1) {oper_stack.push(s[i]);cacl_flag = 1;} else if(prio[s[i]] == 2) {oper_stack.push(s[i]);cacl_flag = 2;} else if (prio[s[i]] == 3) {cacl_flag = 3;STATE = NUM_STATE;break;} else if (s[i] == ')') {calculate(num_stack,oper_stack);break;} else if(s[i] >= '0' && s[i] <= '9') {STATE = NUM_STATE;i--;} else {print_erro("string is not leagal \n",__LINE__);}break;default:break;}}if (number != 0) {num_stack.push(number);calculate(num_stack,oper_stack);}if (number == 0 && num_stack.empty()) {return 0;}while(!oper_stack.empty() && num_stack.size() != 1) {calculate(num_stack,oper_stack);}if (!oper_stack.empty()) {print_erro("string is not leagal", __LINE__);}return num_stack.top();
}int main() {string s;cout << "input the string " << endl;cin >> s;int a = state_change(s);cout << "calcute the result is " << a << endl;return 0;
}
测试如下:
(((1+5)/2+6*9+10)-(2+3)*100)
calcute the result is -433
如若需要计算器支持浮点运算,即在数字状态过程中对小数点做特殊处理即可,同时需要将数字栈声明为double型
相关文章:

javascript小数相减会出现一长串的小数位数的原因
javascript小数相减会出现一长串的小数位数的原因 <script>var a38.8;var b6.8;alert(parseFloat(a)-parseFloat(b));var a134.22;var b6;alert(a*b);</script>以上代码为什么产生一长串小数位出来,虽然比较精确,可没必要呀。这个和数据结构…

Java孩子父母类,@Output孩子和父母之间的沟通 . 角2(5)
我正在尝试学习角度2,并且我正在尝试使用来自我的子组件的数据在父组件中设置变量 . 基本上我在父视图中有一个子 Headers ,我希望 Headers 和一些HTML根据加载的子项进行更改 .父组件:import { Component, OnInit, ViewEncapsulation } from…

SQL 自学笔记1(W3School)
自学W3Schoolhttp://www.w3school.com.cn/sql/index.asp 简介 SQL是什么? Structured Query Language 结构化的查询语言 SQL能做什么? 面向数据库查询、取出数据、插入新数据、更新数据、删除数据在数据库中建立库、表;创建存储过程及视图可设…
BZOJ 1096: [ZJOI2007]仓库建设
传送门 斜率优化DP入门题 显然如果在一个位置 i 建一个仓库,且上一个仓库位置为 j 那么从 j1到 i 的物品显然都要存在 i 仓库是最优的 设 $f [ i ]$ 表示在第 i 个工厂建设仓库时,工厂 1 到 i 的物品都转移好的最小花费 考虑上一个仓库的位置 j 设工厂 i…

C++的STL 堆 实现获取数组堆第K大的数
前言 堆数据结构 使用的是优先级队列实现,创建堆的时候需要指定堆中元素的排列方式,即最大堆或者最小堆 最大堆即 堆顶元素为堆中最大的元素 最小堆即 堆顶元素为堆中最小堆元素 如下为一个最大堆 回到文章标题,获取一个数组中第K大的数&a…

HTML+CSS布局技巧及兼容问题【阅读季】
在IE6和IE7中,行高值必须大于字体的2px以上才能保证字体的完整显示或当作为链接时能显示下划线。 IE6 下去掉 input等元素 的边框 border: 0 none; 所有浏览器都可以了 边框1px {td不重叠状态}:border-collapse: collapse;(table、td需同时…

php 去掉数组相同元素,php怎么去掉数组中重复的元素
php去掉数组中重复的元素的方法:可以通过内置函数array_unique()来实现。array_unique()函数可以移除数组中重复的值并返回过滤后的数组。如果数组中存在多个相同元素,则只保留第一个值。php为我们提供了专门的内置函数array_unique()来解决此问题。该函…

Office文件的奥秘——.NET平台下不借助Office实现Word、Powerpoint等文件的解析(完)...
原文 http://www.cnblogs.com/mayswind/archive/2013/04/01/2991271.html 【题外话】 这是这个系列的最后一篇文章了,为了不让自己觉得少点什么,顺便让自己感觉完美一些,就再把OOXML说一下吧。不过说实话,OOXML真的太容易 解析了&…

Makefile (2) gdb
gdb调试 1.用debug的方式编译 -g 2.打上断点 3.单步调试 step into 进入函数里面step over 运行整个函数step return 跳出当前函数 4.继续运行 5.打印和监控值 下面是栗子: 1 #include <stdlib.h>2 #include <stdio.h>3 4 static int add(int i) //创…

C++的 STL堆 实现获取中位数
前言 堆数据结构 使用的是优先级队列实现,创建堆的时候需要指定堆中元素的排列方式,即最大堆或者最小堆 最大堆即 堆顶元素为堆中最大的元素 最小堆即 堆顶元素为堆中最小堆元素 如下为一个最大堆 中位数: 一组数排序后,如果元…

php 变更 obj,PHP: 不向后兼容的变更 - Manual
不向后兼容的变更PHP 核心中不向后兼容的变更以数组形式访问非数组尝试以数组方式访问 null,bool,int,float 或 resource(例如 $null["key"])将会抛出 notice 通知。fn 关键词fn 成为了保留关键词。需要特别注意,它不能…

正由另一进程使用,因此该进程无法访问此文件。
相信很多人都遇到过这样的问题吧 最近我的电脑似乎有点抽风了,不知道为什么控制台程序,只要使用 开始执行(不调试) 必然就残留在进程中 而且进程管理器看不到~~ 最恶心的是,就算重启VS也还是不能生成 经过一些尝试后发现在cmd中tasklist可以看到这个进程 这就好办了 使用taskki…

mysql5.6下主主复制的配置实现
两台虚拟机192.168.183.131和192.168.183.132,装完系统之后直接把所有开发包都装上 下载软件包mysql-5.6.10.tar.gz,cmake-2.8.10.2.tar.gz(从5.5开始mysql使用cmake来进行编译了而不是之前的configure) mysql的编译安装 1.首先安装cmake [ro…

RSA加密传输代码示例
RSA加密传输代码示例 涉及敏感数据的传输,双方最好约定使用加密解密。那RSA非对称加密就大有作为了。服务端可以保留自己的私钥,发给客户端对应的公钥。这样就可以互相加解密了。php中rsa加解密实现: 首先要生成一对公钥私钥。前提是linux机器…

贪心:assign cookies分糖果
贪心算法的核心: 遵循某种规律,使用最少的资源来完成目标 所以在了解贪心算法的时候需要明确两点 寻找共有的规律每一步的迭代使用最优的策略(消耗最少的资源) 问题如下: 已知一些孩子和一些糖果,每个孩…

mimo系统matlab,OFDM—MIMO系统的matlab程序
【实例简介】MIMO OFDM Simulator:OFDM.m: OFDM Simulator (outer function)create_channel.m: Generates a Rayleigh fading frequency-selective channel, parametrized by the antenna configuration, the OFDM configuration, and the power-delay profile.svd_decompose_c…

软件行业项目经理主要的职责是什么?(转)
项目经理职责:1、 基本职责就是确保项目目标的实现,领导项目团队准时、优质地完成全部工作。2、 与客户沟通,了解项目的整体需求。并与客户保持一定的联系,即时反馈阶段性的成果,和即时更改客户提出的合理需求。3、 制…

android interview 1
1. 请描述下Activity的生命周期。 必调用的三个方法:onCreate() --> onStart() --> onResume(),用AAA表示(1)父Activity启动子Activity,子Actvity退出,父Activity调用顺序如下AAA --> onF…

Spring Boot 的 10 个核心模块
学习 Spring Boot 必须得了解它的核心模块,和 Spring 框架一样,Spring Boot 也是一个庞大的项目,也是由许多核心子模块组成的。 你所需具备的基础 告诉你,Spring Boot 真是个牛逼货!Spring Boot 核心配置文件详解Sprin…

贪心:Wiggle Subsequence 摇摆序列
一个整数序列,如果两个相邻元素的差恰好正负(负正)交替出现,则该序列被称为 摇摆序列。一个小于2个元素的序列直接为摇摆序列。给一个随机序列,求这个序列满足摇摆序列定义的最长子序列的长度: 输入[1,17,5,10,13,15,10,5,16,8]&…

php 腾讯云实时音视频,腾讯云视频 -实时音视频学习日志
1、实时音视频功能h5只支持ios2、不能主动拉人建群3、pc端的demo研究整体流程可以按照腾讯音视频上面指导的步骤走,申请账号,创建应用,购买套餐。购买好套餐后然后记录sdkappid、accountType。下载密钥。在开发辅助里面有个签名(UserSig)生成…

juery mobile select下来菜单选项提交form问题
注意: data-native-menu"false" 虽然具有渲染作用,但是无法进行js提交。 <script type"text/javascript"> $(function() { $("#category").change(function() { loadData(); }); }); function loadData(){ documen…

android GridView item中组件获取焦点
2019独角兽企业重金招聘Python工程师标准>>> 项目中在使用GridView控件时,里面的item有imageView、buttion等子控件。 但是GridView默认焦点是让item获取焦点,所以要使子控件获取焦点的话,要在gridview的属性中设置: …

Login failed for user 'NT AUTHORITY\SYSTEM'. 原因: 无法打开明确指定的数据库。异常处理...
公司一台SQL Server服务器一直报 "Login failed for user NT AUTHORITY\SYSTEM. 原因: 无法打开明确指定的数据库。"错误,按网上所讲的正常的处理方式都没有解决。 最后是发现一个公司内部人员写的服务造成的,将服务停用即可。转载于:https://…

n-netstat 查看网络状态命令
文章目录前言语法格式输出含义使用实例列出端口占用情况 (包括监听和未监听的)列出所有处于监听状态的 Sockets显示每个协议的统计信息在 netstat 输出中显示 PID 和进程名称在 netstat 输出中不显示主机,端口和用户名 (host, port or user)持续输出 netstat 信息显…

php win memcached 5.4,CentOS 5.4下Memcache的安装步骤(Linux+Nginx+PHP+Memcached) 电脑维修技术网...
一、源码包准备服务器端主要是安装memcache服务器端,目前的最新版本是 memcached-v1.4.4 。下载:http://memcached.googlecode.com/files/memcached-1.4.4.tar.gz另外,Memcache用到了libevent这个库用于Socket的处理,所以还需要安…

LomoX 桌面UI框架更新,增加资源管理
修改: 1.增加lxoption工具类,提供启动的兼容,兼容旧版的,并支持注册资源启动 (蔡东赟)兼容启动项目:main.lx //资源包默认现在用 qrc:/pack/main.html 后面评估,或者等编辑器出来mai…

Python 数据类型:列表
一、列表介绍 1. 列表可以存储一系列的值,使用中括号来定义,每个元素之间用逗号隔开,形如 [a, b, c, d]2. 列表与元组的区别是:列表中的元素是可变的,元组中的元素是不可变的 In [1]: list1 [] # 定义一个空列…

贪心:remove K digits移除K个数字
问题描述: 已知一个使用字符串表示的非负整数num,将num中的k个数字移 除,求移除k个数字后,可以获得的最小的可能的新数字。 例如:num “1432219” , k 3 在去掉3个数字后得到的很多很多可能里,如1432、43…

oracle 分组排序 update,oracle分组排序
oracle 分组排序:这个麻烦:SELECT * FROM (SELECT deptno,ename,sal,ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal DESC ) Top3 FROM emp)WHERE Top3 < 3开窗函数也ok:代码简单点:where 11 and status2JOIN( select p…