简单算术表达式C++实现
来源:互联网 发布:算法与并行计算 编辑:程序博客网 时间:2024/06/15 11:35
输入的算术表达式是中缀表达式,由于操作符的优先级不同,不能直接进行求解,而后缀表达式的计算不需要判别操作符的优先级,所以我实现算术表达式的思路是:1)应用堆栈将中缀表达式转化为后缀表达式,2)用堆栈实现后缀表达式求值。
用堆栈实现后缀表达式求值的过程:从左到右读入后缀表达式的各项,并根据读入的对象判断执行何种操作,有以下3中情况:
1) 当读入的是一个运算数时,把它压入栈中;
2) 当读入的是一个运算符时,就从栈中弹出适当数量的运算数并进行计算,计算结果再压回到栈中;
3) 处理完整个后缀表达式之后,栈顶上的元素就是表达式的结果。
应用堆栈将中缀表达式转换为后缀表达式的基本过程为:从头到尾读取中缀表达式的每个对象,对不同对象按不同情况处理:
1) 如果遇到空格则认为是分隔符,无需处理;
2) 若遇到运算数,则直接输出;
3) 若是左括号,则将其压入至栈中;
4) 若遇到的是右括号,表明括号内的中缀表达式已经扫描完毕,将栈顶的运算符弹出并输出,直到遇到左括号(左括号也出栈,但不输出);
5) 若遇到的是运算符,若该运算符的优先级大于栈顶运算符的优先级,则把它压入栈中;若该运算符的优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出,在比较新的栈顶运算符,按这样的处理方法,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈;
6) 若中缀表达式中的各对象处理完毕,则把堆栈中保留的运算符一并输出。
在代码实现的过程中,首先我们要定义一个栈,因为在后缀表达式求值的过程中,栈是用来存运算数的;在中缀转换为后缀表达式的过程中,栈是用来存放操作符的。所以在实现栈的时候我用了模板。栈的实现如下:
// Stack.h
#include<vector>template <class T>class Stack{public: void push(const T&); T pop(); T peek();//该函数只是返回最顶端的元素,并不删除 bool empty();private: std::vector<T> _stack;};template<class T>void Stack<T>::push(const T& a){ _stack.push_back(a);}template<class T>T Stack<T>::pop(){ //在要用到出栈的时候一定要保证栈不为空 auto it = _stack.end(); auto c = *(it - 1); _stack.pop_back(); return c;}template<class T>bool Stack<T>::empty(){ return _stack.begin() == _stack.end();}template<class T>T Stack<T>::peek(){ auto it = _stack.end(); return *(it - 1);}
定义相应的运算符的优先级,我用整数的大小来定义优先级的大小,对应的函数实现如下:
int op_pri(const char& a){ switch (a){ case ')': return 0; case '+':case '-': return 1; case '*':case'/': return 2; case '(': return 3; }}
在实现优先级的时候,当输入为左括号时,需要无条件进栈,所以左括号的优先级要最高。碰到右括号时要无条件出栈直到那个栈顶的操作符是左括号。所以右括号的优先级我定义为最低。但是要注意当当前的运算符为右括号时,证明括号内的中缀表达式已经扫描完毕,要将栈顶运算符弹出,直到左括号(这时左括号出栈,但是不用加入到运算中);还要注意当运算符是左括号时,因为我把左括号定义为了最高优先级了,如果按正常的情况,当栈顶是左括号时,应当会马上输出但是这不符合我们的要求,希望的是紧接的运算符能无条件的入栈,所以在代码的实现过程中这是中特殊的情况用个if语句强调。
接下来是对中缀转换为后缀表达式实现的最主要的功能函数,就是运算符的出入栈的情况:
int oper_cp(const char&a, const char& b){ int c = op_pri(a); int d = op_pri(b); if (c == 0 && d == 3) return -1;//当左括号碰到右括号时,定义为一个特殊状态,此状态是直接把栈中的左括号操作符弹出 //右括号也不进栈 else if (d == 3)//定义优先级时,以整数大小来对应优先级的大小。但是当输入为左括号时,需要无条件 //进栈,所以左括号的优先级要最高。碰到右括号时要无条件出栈直到那个栈顶的操作符是左括号。所以 //右括号的优先级要最低。 //但是在右括号进栈后,若紧接的操作符是+、-、*、/的话,需要进栈,这个条件语句就是在这种情况下 //对应的操作符直接进栈 return 1; else if (c > d){ return 1; } else return 0;}
有了上述两个函数的支持,接下来就是直接对中缀表达式求值的函数,这些问题只是逻辑问题,我的代码实现如下:
void exp(Stack<double> &val, Stack<char> &op){ char c{}; string s{}; do { c = getchar(); if ((c >= '0'&&c <= '9') || c == '.') { s.push_back(c); continue; } else { if (s != "\0") { val.push(atof(s.c_str())); s = "\0"; } } if (c == '+' || c == '-' || c == '*' || c == '/' || c == ')' || c == '(') { char b; if (op.empty()){ op.push(c); continue; } while (1) { if (!op.empty()) b = op.peek(); else { op.push(c); break; } int m = oper_cp(c, b); if (m == 1) { op.push(c); break; } if (m == 0) { b = op.pop(); double c, d; d = val.pop(); c = val.pop(); switch (b) { case '+': val.push(c + d); break; case '-': val.push(c - d); break; case'*': val.push(c*d); break; case'/': val.push(c / d); break; } continue; } if (m == -1) { op.pop(); break; } } } } while (c != '\n'); while (!op.empty()){ char b = op.pop(); double e, d; d = val.pop(); e = val.pop(); switch (b) { case '+': val.push(e + d); break; case '-': val.push(e - d); break; case'*': val.push(e*d); break; case'/': val.push(e / d); break; } }}
调用这些函数的main函数如下:
#include<iostream>#include<string>#include "Stack.h"using namespace std;void exp(Stack<double> &val, Stack<char> &op);int op_pri(const char& );int oper_cp(const char&a, const char& b);int main(){ Stack<double> val; Stack<char> op; exp(val, op); cout << val.pop();}int oper_cp(const char&a, const char& b){ int c = op_pri(a); int d = op_pri(b); if (c == 0 && d == 3) return -1;//当左括号碰到右括号时,定义为一个特殊状态,此状态是直接把栈中的左括号操作符弹出 //右括号也不进栈 else if (d == 3)//定义优先级时,以整数大小来对应优先级的大小。但是当输入为左括号时,需要无条件 //进栈,所以左括号的优先级要最高。碰到右括号时要无条件出栈直到那个栈顶的操作符是左括号。所以 //右括号的优先级要最低。 //但是在右括号进栈后,若紧接的操作符是+、-、*、/的话,需要进栈,这个条件语句就是在这种情况下 //对应的操作符直接进栈 return 1; else if (c > d){ return 1; } else return 0;}int op_pri(const char& a){ switch (a){ case ')': return 0; case '+':case '-': return 1; case '*':case'/': return 2; case '(': return 3; }}void exp(Stack<double> &val, Stack<char> &op){ char c{}; string s{}; do { c = getchar(); if ((c >= '0'&&c <= '9') || c == '.') { s.push_back(c); continue; } else { if (s != "\0") { val.push(atof(s.c_str())); s = "\0"; } } if (c == '+' || c == '-' || c == '*' || c == '/' || c == ')' || c == '(') { char b; if (op.empty()){ op.push(c); continue; } while (1) { if (!op.empty()) b = op.peek(); else { op.push(c); break; } int m = oper_cp(c, b); if (m == 1) { op.push(c); break; } if (m == 0) { b = op.pop(); double c, d; d = val.pop(); c = val.pop(); switch (b) { case '+': val.push(c + d); break; case '-': val.push(c - d); break; case'*': val.push(c*d); break; case'/': val.push(c / d); break; } continue; } if (m == -1) { op.pop(); break; } } } } while (c != '\n'); while (!op.empty()){ char b = op.pop(); double e, d; d = val.pop(); e = val.pop(); switch (b) { case '+': val.push(e + d); break; case '-': val.push(e - d); break; case'*': val.push(e*d); break; case'/': val.push(e / d); break; } }}
- 简单算术表达式C++实现
- 算术表达式计算C实现
- 利用栈实现简单算术表达式求值
- 简单算术表达式求值
- 简单算术表达式求值
- 简单算术表达式求值
- C语言 算术表达式
- 栈的操作和c语言实现算术表达式求值
- 简单算术表达式的使用
- 算术表达式求值@C/C++
- Objective-C的算术表达式
- 算术表达式求解java实现
- 算术表达式的Java实现
- c语言算术运算符和算术表达式整理学习
- C语言算术运算符和算术表达式
- C语言算术运算符和算术表达式
- C语言中的算术运算符和算术表达式
- C语言:算术运算符与算术表达式
- 非常量引用的初始值必须为左值的问题
- Executor框架结构
- scp命令
- JAVA采用CXF框架开发基于JAX-WS(SOAP)规范的WebService服务器端
- MySQL学习历程(一):安装和配置
- 简单算术表达式C++实现
- Android 学习笔记一:创建一个Hello World
- poj 1625(ac自动机+dp+高精度)
- Linux之yum在线安装
- Android 学习笔记二:Android项目的结构
- FZU Problem F 单纵大法好 (贪心,set容器) *
- Android 学习笔记三:Activity
- java连接mysql(2)
- Android TabLayout定制CustomView与ViewPager交互双向联动