首页 > C++的STL 栈 实现四则运算

C++的STL 栈 实现四则运算

使用栈实现四则运算,支持+,-,*,/,(,)

输入为字符串,输出为计算好的数值,如不符合四则运算的规定,则异常退出

这个实现借用了栈以及字符处理状态机的思想:

  1. 维护两个栈:一个用于数值,另一个用于存放计算符号
  2. 字符状态机用于遍历输入的字符串过程中进行对应数值处理和计算符号处理的状态转换

在第一个思想中:符号栈中存在优先级,即*和/的优先级高于+和-,同时括号的优先级高于*和/,所以符号栈的入栈顺序以及触发计算时机需要在状态机转动的过程中谨慎处理。

入栈基本过程类似如下:

对于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
",__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
",__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 
",__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 
", __LINE__);}result = num2 / num1; //数值反转进行计算} else { print_erro("operator failed
", __LINE__);}oper_stack.pop();num_stak.push(result);
}

完整代码如下:

#include 
#include 
#include 
#include 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 
", __LINE__);}result = num2 / num1;} else { print_erro("operator failed
", __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
",__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
",__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 
",__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型

更多相关:

  • 协议36.508 4.5节 有个表格写的很清楚: Table 4.5.2.3-1: UE registration procedure (state 1 to state 2)...

  • 最近的诸多面试经历确实让自己发现内功还不够,还需要持续的学习精进。 实现如下: class RWLock{private:int state;mutex mu;condition_variable cond;public:RWLock():state(0){}void rlock(){mu.lock();while(state <...

  • #include #include #include #include #include #include #include

  • 题目:表示数值的字符串 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、"5e2"、"-123"、"3.1416"、"0123"及"-1E-16"都表示数值,但"12e"、"1a3.14"、"1.2.3"、"+-5"及"12e+5.4"都不是。 解题: 数值错误的形式有多种多样,但是正确的...

  • 加法伺候  //超过20位数值相加---------------------------------------- function bigNumAdd(a, b) {if (!(typeof a === "string" && typeof b === "string")) return console.log("传入参数必...

  • 业务场景: 从中文字句中匹配出指定的中文子字符串 .这样的情况我在工作中遇到非常多, 特梳理总结如下. 难点: 处理GBK和utf8之类的字符编码, 同时正则匹配Pattern中包含汉字,要汉字正常发挥作用,必须非常谨慎.推荐最好统一为utf8编码,如果不是这种最优情况,也有酌情处理. 往往一个具有普适性的正则表达式会简化程...

  • 简单record 一下 #include // 'struct sockaddr_in' #include #include // 'struct ifreq' and 'struct if_nameindex' #include #inc...

  • 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。 注意: num 的长度小于 10002 且 ≥ k。 num 不会包含任何前导零。 示例 1 : 输入: num = “1432219”, k = 3 输出: “1219” 解释: 移除掉三个数字 4, 3, 和 2形成一个新的最小的数...

  • 代码展示:   http://paste.ubuntu.com/23693598/ #include #include #include char * largeDiffer(char *a,char *b){ /*  使用说明 传入的a和b只能为整数 结果为a-b;返回...

  • Description We all know that Bin-Laden is a notorious terrorist, and he has disappeared for a long time. But recently, it is reported that he hides in Hang Zhou of Ch...

  • /*Name: NYOJ--811--变态最大值Author: shen_渊 Date: 17/04/17 15:49Description: 看到博客上这道题浏览量最高,原来的代码就看不下去了 o(╯□╰)o */#include #include #include u...

  • 生成唯一号:思路,根据yymmddhhmmss+自增长号+唯一服务器号( SystemNo)生成唯一码,总长度19,例如:1509281204550000101. public class UniqueNumber {     private static long num = 0;//流水号     private sta...