2、输入表达式,输出值。分两种情况:中缀表达式和后缀表达式。
中缀表达式求值:先将中缀表达式建立二叉树转后缀表达式,然后再求值。
尝试1:
#include <iostream>
#include <string>
#include <cmath>
#include <cstdlib>//sum1=atof(t1.c_str());
using namespace std;
//后缀表达式求值,这种方式的弊端很明显,只能计算单个位置的数据,不能出现多位数和小数,原因是我这里每次取数是expression[i]造成的
double postfix_expression(string expression){
//56+2*3+
double stack[20];//操作数栈
int top = -1;//栈顶指针
for(int i=0;i<expression.length();i++){
if(expression[i]=='+'){
double d = stack[top];//栈顶指针在top
top--;
double c = stack[top];
stack[top]=d+c;
cout<<d<<"+"<<c<<"="<<stack[top]<<endl;
}else if(expression[i]=='-'){
double d = stack[top];
top--;
double c = stack[top];
stack[top]=c-d;
cout<<c<<"-"<<d<<"="<<stack[top]<<endl;
}else if(expression[i]=='*'){
double d = stack[top];
top--;
double c = stack[top];
stack[top]=c*d;
cout<<d<<"*"<<c<<"="<<stack[top]<<endl;
}else if(expression[i]=='/'){
double d = stack[top];
top--;
double c = stack[top];
stack[top]=c/d;
cout<<c<<"/"<<d<<"="<<stack[top]<<endl;
}else if(expression[i]>='0' and expression[i]<='9'){
top++;
string s = expression.substr(i,1);
double c = atof(s.c_str());
stack[top]=c;
}else{
cout<<"输入错误!"<<endl;
exit(0);
}
}
return stack[top--];
}
int main()
{
// string ex;
// cout<<"请输入后缀表达式:";
// cin>>ex;
//用例:3*(5+4)/8+4*(5+2)
cout<<postfix_expression("54+3*8/52+4*+")<<endl;
return 0;
}
猜想,我们对数字的判断应该在之前就判断完毕,因为后缀表达式中,如:54+3*8/52+4*+,是比较难确定54还是5 4 当然可以用操作符的个数匹配,但是比较麻烦。这里,我们可以用中缀表达式,也就是原来输入的数据表达式,然后我们截取数据放入集合中,集合的类型是vector<string>,我们在使用后缀表达式的时候,转换数据就会比较方便。下面关键是如何处理由中缀表达式向后缀表达式转化。
参考数据结构:
需要用操作符的优先级进行栈运算。用icp(in coming priority)表示当前扫描到的运算符的优先级,用isp(in stack priority)表示该运算符进栈后的优先级。
操作符 | # | ( | * / | + - | ) |
isp | 0 | 1 | 5 | 3 | 6 |
icp | 0 | 6 | 4 | 2 | 1 |
举例说明:3*(5+4)/8+4*(5+2)
中缀表达式:3*(5+4)/8+4*(5+2) 后缀表达式:354+*8/452+*+
步骤 | 扫描项 | 项类型 | 动作 | 字符栈内内容 | 输出 |
0 |
|
| ‘#’进栈,读取下一字符 | # |
|
1 | 3 | 操作数 | 直接输出 | # | 3 |
2 | * | 操作符 | isp(#)<icp(*),进栈 | #* |
|
3 | ( | 操作符 | isp(*)<icp((),进栈 | #*( |
|
4 | 5 | 操作数 | 直接输出 | #*( | 5 |
5 | + | 操作符 | isp(()<icp(+),进栈 | #*(+ |
|
6 | 4 | 操作数 | 直接输出 |
| 4 |
7 | ) | 操作符 | isp(+)>icp()),出栈 | #*( | + |
|
|
| isp(()==icp()),退栈 | #* |
|
8 | / | 操作符 | isp(*)>icp(/),出栈 | # | * |
|
|
| isp(#)<icp(/),出栈 | #/ |
|
9 | 8 | 操作数 | 直接输出 |
| 8 |
10 | + | 操作符 | isp(/)>icp(+),出栈 | # | / |
11 |
|
| isp(#)<icp(+),进栈 | #+ |
|
12 | 4 | 操作数 | 直接输出 |
| 4 |
13 | * | 操作符 | isp(+)<icp(*),进栈 | #+* |
|
14 | ( | 操作符 | isp(*)<icp((),进栈 | #+*( |
|
15 | 5 | 操作数 | 直接输出 |
| 5 |
16 | + | 操作符 | isp(()<icp(+),进栈 | #+*(+ |
|
17 | 2 | 操作数 | 直接输出 |
| 2 |
18 | ) | 操作符 | isp(+)>icp()),出栈 | #+*( | + |
|
|
| isp(()==icp()),退栈 | #+* |
|
19 | # | 操作符 | isp(*)>icp(#),出栈 | #+ | * |
|
|
| isp(+)>icp(#),出栈 | # | + |
|
|
| isp(#)==icp(#),退栈结束 | #) |
|
就可以得到中缀表达式,所以这里需要使用优先级比较+栈
#include <iostream>
#include <string>
#include <cmath>
#include <vector>
#include <cstdlib>//sum1=atof(t1.c_str());
using namespace std;
/*
操作符 # ( * / + - )
isp 0 1 5 3 6
icp 0 6 4 2 1
*/
//四则运算,栈内>入栈,而且*/一定高于+-;括号,栈内<入栈, 站内尾大,入栈头大,占两端
// 前期思考数据封装函数,最后演化成 transform_postfix 中的中心架构
vector<double> data_package(string expression){
vector<double> vc;
int index=0, count=0;//记录需要截取字符串的下标位置
for(int i=0;i<expression.length();i++){
//3*(5+4)/8+4*(5+2)
if(expression[i]=='+' or expression[i]=='-' or expression[i]=='*' or expression[i]=='/' or expression[i]==')' or expression[i]=='('){
if(count!=0){
string s=expression.substr(index, count);//使用截取而不是直接expression[i],是因为写入字符,是字符地址后面的一大坨字符(首地址)
double num = atof(s.c_str());
vc.push_back(num);
}
index=i+1;
count=0;
}
else {
count++;
}
}
return vc;
}
//3*(5+4)/8+4*(5+2)
//为了方便+-*/()表示为:335516 224461
int get_isp(char a){
if(a=='+' or a=='-')
return 3;
else if(a=='*' or a=='/')
return 5;
else if(a=='(')
return 1;
else if(a==')')
return 6;
else if(a=='#')
return 0;
}
int get_icp(char a){
if(a=='+' or a=='-')
return 2;
else if(a=='*' or a=='/')
return 4;
else if(a=='(')
return 6;
else if(a==')')
return 1;
else if(a=='#')
return 0;
}
string transform_op_stack_to_string(char a){
//op_stack[top]
if(a=='+')
return "+";
else if(a=='-')
return "-";
else if(a=='*')
return "*";
else if(a=='/')
return "/";
}
//思路来源于上面的:data_package
string transform_postfix(string expression){
//这里也要完成表达式的封装vector<string>
vector<double> vc = data_package(expression);
char op_stack[20];//+-*/():335516 224461
int top = -1;
top++;
op_stack[top]='#';
string str="";
int index=0, count=0;//记录需要截取字符串的下标位置
int i=0;
while(top!=-1){
if(i==expression.length()){
expression.append("#");//因为栈可能没出完,而表达式判断已经到了末尾
}
if(expression[i]=='+' or expression[i]=='-' or expression[i]=='*' or expression[i]=='/' or expression[i]==')' or expression[i]=='#' or expression[i]=='('){
//数字在前
if(count!=0){
string s=expression.substr(index, count);
str.append(s);
str.append(" "); //数字,直接输出
}
index=i+1;
count=0;
//符号判断在后
//isp icp 大,进;小,顶出;等,退
if(get_isp(op_stack[top])<get_icp(expression[i])){
top++;
op_stack[top]=expression[i];
}else if(get_isp(op_stack[top])>get_icp(expression[i])){
bool flag = true;//是否循环
while(flag){//使用标识,进栈或者退栈,就退出循环
if(get_isp(op_stack[top])>get_icp(expression[i])){
//小 ,顶出
str.append(transform_op_stack_to_string(op_stack[top])+" ");
//这里之所以要把char 转为 string ,是因为使用char 数组,加入的是该地址后的所有的字符
// cout<<op_stack[top]<<"顶出"<<"此时的比较元素是:"<<expression[i]<<endl;
top--;
}else if(get_isp(op_stack[top])<get_icp(expression[i])){//大,进
top++;
op_stack[top]=expression[i];
flag = false;//不再循环
// cout<<op_stack[top]<<"进栈"<<endl;
}else if(get_isp(op_stack[top])==get_icp(expression[i])){
flag = false;//不再循环
// cout<<op_stack[top]<<"退栈"<<endl;
top--;//等,退
}
}
}else if(get_isp(op_stack[top])==get_icp(expression[i])){
top--;//等,退
}
}else {
count++;
}
i++;
}
cout<<"后缀表达式的结果:"<<str<<endl;
return str;
}
//初始版本(已抛弃):后缀表达式求值,这种方式的弊端很明显,只能计算单个位置的数据,不能出现多位数和小数,原因是我这里每次取数是expression[i]造成的
double postfix_expression(string expression){
//56+2*3+
double stack[20];//操作数栈
int top = -1;//栈顶指针
cout<<"计算的过程如下:"<<endl;
for(int i=0;i<expression.length();i++){
if(expression[i]=='+'){
double d = stack[top];//栈顶指针在top
top--;
double c = stack[top];
stack[top]=d+c;
cout<<d<<"+"<<c<<"="<<stack[top]<<endl;
}else if(expression[i]=='-'){
double d = stack[top];
top--;
double c = stack[top];
stack[top]=c-d;
cout<<c<<"-"<<d<<"="<<stack[top]<<endl;
}else if(expression[i]=='*'){
double d = stack[top];
top--;
double c = stack[top];
stack[top]=c*d;
cout<<d<<"*"<<c<<"="<<stack[top]<<endl;
}else if(expression[i]=='/'){
double d = stack[top];
top--;
double c = stack[top];
stack[top]=c/d;
cout<<c<<"/"<<d<<"="<<stack[top]<<endl;
}else if(expression[i]>='0' and expression[i]<='9'){
top++;
string s = expression.substr(i,1);
double c = atof(s.c_str());
stack[top]=c;
}else{
cout<<"输入错误!"<<endl;
exit(0);
}
}
return stack[top--];
}
//改进
double postfix_expression_fix(string expression){
//56+2*3+
double stack[20];//操作数栈
int top = -1;//栈顶指针
int count=0, index=0;
//测试的结果:3 5 4 + * 8 / 4 5 2 + * + 用空格分割
for(int i=0;i<expression.length();i++){
if(expression[i]=='+' or expression[i]=='-' or expression[i]=='*' or expression[i]=='/' or expression[i]==')' or expression[i]==' ' or expression[i]=='('){
//数字在前
if(count!=0){
string s=expression.substr(index, count);
// cout<<"操作数:"<<s<<endl;//测试
top++;
stack[top]=atof(s.c_str()); //字符串转化为double,加入栈
}
index=i+1;
count=0;
//判断符号
if(expression[i]=='+'){
double d = stack[top];//栈顶指针在top
top--;
double c = stack[top];
stack[top]=d+c;
cout<<d<<"+"<<c<<"="<<stack[top]<<endl;
}else if(expression[i]=='-'){
double d = stack[top];
top--;
double c = stack[top];
stack[top]=c-d;
cout<<c<<"-"<<d<<"="<<stack[top]<<endl;
}else if(expression[i]=='*'){
double d = stack[top];
top--;
double c = stack[top];
stack[top]=c*d;
cout<<d<<"*"<<c<<"="<<stack[top]<<endl;
}else if(expression[i]=='/'){
double d = stack[top];
top--;
double c = stack[top];
stack[top]=c/d;
cout<<c<<"/"<<d<<"="<<stack[top]<<endl;
}else if(expression[i]>='0' and expression[i]<='9'){
top++;
string s = expression.substr(i,1);
double c = atof(s.c_str());
stack[top]=c;
}
}else{
count++;
}
}
return stack[top--];
}
int main()
{
string expression;
cout<<"请输入中缀表达式:";
cin>>expression;
//用例:3*(5+4)/8+4*(5+2)
string postfix = transform_postfix(expression);//后缀表达式:354+*8/452+*+
double result = postfix_expression_fix(postfix);
cout<<"表达式:"<<expression<<",计算的结果是:"<<result<<endl;
return 0;
}
下面是使用电脑计算器计算的结果:
作者: 无涯明月