C++实现任意表达式求值(栈)
2010-02-16 10:51
295 查看
今天花了大概四个小时时间,用栈(stack)实现了“任意表达式的值计算”的问题。
C++ 比 C 好的一点就是,C++ 的STL定义了大量的数据类型和算法,相比于 C 更加视觉化。
实现这个的基本思路很简单:分成两部分完成。两个主要函数:
string shorten(string m) 把 string m 由中缀式变为右缀式,double calculate(string s) 计算右缀式的表达式值。
数字写入右缀式m很简单,不过别忘了用个符号把数字分开。我选择的是$。
比较难的地方是shorten函数,分析怎样把 string m 变为右缀式。可能的计算有这么几种:+,-,*,/,()。于是我通过列表的方式来分析:
+|- *|/ ( 空
+|- m+=c m+=c push push
*|/ push m+=c push push
( push push push push
) m+=c m+=c m+=c XXXX (XXXX表示不可能发生的情况)
竖行是操作符,横行是对应每一个竖行可能遇到的情况,“空”代表栈为空。push表示入栈,m+=c表示元素出栈,写入表达式(右缀式)m。
其实列表的原则挺简单的:
1. 把“(”看做开辟一次新的栈(从“(”开始算,忽视之前的元素,直到“)”被取消);
2. 元素a遇到相同或更高优先级的,栈顶元素c出栈,给右缀表达式m;再次对比;直到遇到更高优先级的,元素a入栈;
3. “)”出现的时候,之前所有元素依次出栈,写入m,直到“(”;
4. 在数字都加入右缀表达式之后,栈中所有元素依次出栈,写入m,直到栈为空。
关键就是 2、3条,我花了好久才总结出来的规律。顺便说下,列表法真的是很好的分析问题的方式,不重不漏还简练。
然后进行右缀表达式的计算,这个比较简单:数字依次入栈,遇到操作符后对栈顶的两个元素进行顺序操作(倒数第二个 +-*/ 倒数第一个),然后把这两个元素换成新的结果。如此循环即可。
原题目要求用int即可,但用int必然会造成除法的不精确。所以考虑用double类型,并且在读取的时候可以支持小数点。记得是有直接转化的函数,但忘了,所以自己写啦,命名为 str2double(string s)。有个dec变量决定计算整数部分还是小数部分,详细可参见函数。
这次实践这个程序还有个小收获,是在我无数次的debug之中:可以在某些关键步骤(比较容易发现bug的地方)加上输出语句,这样可以判断程序是否运行过了这些关键地方。
还有,顺便提一下,“模块化”的思想真的很重要,不然在进行一些小改动时,那种“牵一发而动全身”的感觉很焦虑、很凌乱。
C++ 比 C 好的一点就是,C++ 的STL定义了大量的数据类型和算法,相比于 C 更加视觉化。
实现这个的基本思路很简单:分成两部分完成。两个主要函数:
string shorten(string m) 把 string m 由中缀式变为右缀式,double calculate(string s) 计算右缀式的表达式值。
数字写入右缀式m很简单,不过别忘了用个符号把数字分开。我选择的是$。
比较难的地方是shorten函数,分析怎样把 string m 变为右缀式。可能的计算有这么几种:+,-,*,/,()。于是我通过列表的方式来分析:
+|- *|/ ( 空
+|- m+=c m+=c push push
*|/ push m+=c push push
( push push push push
) m+=c m+=c m+=c XXXX (XXXX表示不可能发生的情况)
竖行是操作符,横行是对应每一个竖行可能遇到的情况,“空”代表栈为空。push表示入栈,m+=c表示元素出栈,写入表达式(右缀式)m。
其实列表的原则挺简单的:
1. 把“(”看做开辟一次新的栈(从“(”开始算,忽视之前的元素,直到“)”被取消);
2. 元素a遇到相同或更高优先级的,栈顶元素c出栈,给右缀表达式m;再次对比;直到遇到更高优先级的,元素a入栈;
3. “)”出现的时候,之前所有元素依次出栈,写入m,直到“(”;
4. 在数字都加入右缀表达式之后,栈中所有元素依次出栈,写入m,直到栈为空。
关键就是 2、3条,我花了好久才总结出来的规律。顺便说下,列表法真的是很好的分析问题的方式,不重不漏还简练。
然后进行右缀表达式的计算,这个比较简单:数字依次入栈,遇到操作符后对栈顶的两个元素进行顺序操作(倒数第二个 +-*/ 倒数第一个),然后把这两个元素换成新的结果。如此循环即可。
原题目要求用int即可,但用int必然会造成除法的不精确。所以考虑用double类型,并且在读取的时候可以支持小数点。记得是有直接转化的函数,但忘了,所以自己写啦,命名为 str2double(string s)。有个dec变量决定计算整数部分还是小数部分,详细可参见函数。
这次实践这个程序还有个小收获,是在我无数次的debug之中:可以在某些关键步骤(比较容易发现bug的地方)加上输出语句,这样可以判断程序是否运行过了这些关键地方。
还有,顺便提一下,“模块化”的思想真的很重要,不然在进行一些小改动时,那种“牵一发而动全身”的感觉很焦虑、很凌乱。
#include <iostream> #include <string> #include <stack> #include <fstream> using namespace std; bool isone(char c){ return (c=='+' || c=='-'); } bool istwo(char c){ return (c=='*' || c=='/'); } string shorten(string m){ stack<char> s; string sur; int i; char w; sur; for(i=0;i<m.size();i++){ if(isdigit(m[i]) || m[i]=='.'){ while(isdigit(m[i]) || m[i]=='.') sur += m[i++]; i--; sur += '$'; } else if(isone(m[i])){ while(s.size() && (isone(s.top()) || istwo(s.top()))){ sur+=s.top(); s.pop(); } s.push(m[i]); } else if(m[i]==')'){ while(s.top()!='('){ sur+=s.top(); s.pop(); } s.pop(); } else if(istwo(m[i])){ while(s.size() && istwo(s.top())){ sur+=s.top(); s.pop(); } s.push(m[i]); } else s.push(m[i]); } while(s.size()){ sur+=s.top(); s.pop(); } return sur; } double tentimes(int n){ double res=1; for(int i=0;i<n;i++){ res *= 10; } return res; } double str2double(string s){ double res=0; char c; int dec=0; for(int i=1;i<=s.size();i++){ c=s[i-1]; if(c=='.') dec=i; else if(!dec) res = res*10 + c-'0'; else res += (c-'0')/tentimes(i-dec); } return res; } double calculate(string s){ double res, t; stack<double> num; string temp; int i; for(i=0;i<s.size();i++){ temp=""; if(isdigit(s[i]) || s[i]=='.'){ while(isdigit(s[i]) || s[i]=='.') temp+=s[i++]; //如果最后一位是数字,这样做会出错 num.push(str2double(temp)); } else{ switch (s[i]){ case '+': t=num.top(); num.pop(); t+=num.top();num.pop();num.push(t);break; case '-': t=num.top(); num.pop(); t=num.top()-t;num.pop();num.push(t);break; case '*': t=num.top(); num.pop(); t*=num.top();num.pop();num.push(t);break; case '/': t=num.top(); num.pop(); t=num.top()/t;num.pop();num.push(t);break; default: cerr << "Fatal Error! Result would be wrong!" << endl; system("pause");break; } } } res=num.top(); return res; } int main(){ string mid, sur; cin >> mid; sur = shorten(mid); cout << "successfully executed! The right hand operator expression is: " << endl; cout << sur << endl; cout << "The result is: " <<calculate(sur) << endl; system("pause"); return 0; }
相关文章推荐
- 在单链表的基础上用c++实现的链栈,并使用进制转换,表达式求值两个小程序来测试
- java实现任意四则运算表达式求值算法
- 实现表达式求值(c++实现)
- 数据结构之——用C++实现算术表达式求值
- 分别用C++和JavaScript 实现四则运算表达式求值
- C++实现数据结构作业——表达式求值
- C++实现任意表达时候求值(栈)
- 表达式求值--栈(c++/java实现)
- 用C++实现表达式求值
- 算数表达式求值C++实现
- C++实现表达式求值
- C++ 实现 算数表达式求值
- C++实现中缀表达式转后缀表达式并求值
- 数据结构(19)栈典型问题之C++实现表达式求值
- 表达式求值----c++-----堆栈实现
- 用c++实现中序表达式求值
- 后缀表达式(逆波兰表达式),并求值(可求浮点、负数与大于10的数),C++实现
- C++利用链栈实现表达式求值
- 表达式求值(c++实现)
- C++实现表达式求值(括号,小数点,负数)