最近在学习数据结构与算法,学到栈这里,就基于栈实现了一个简答四则表达式算值的程序。平时我们写的那
种表达式就是中缀,而计算机处理中缀是不占优势的一般都是将中缀转成后缀再计算值,在这里我也利用这个思路,
将中缀表达式分为以下两部:
A.中缀表达式转成后缀表达式,主要有以下几步:
a.初始化一个运算符栈 b.从左到右读取一个字符 c.如果是操作数就直接输出到后缀表达式 d.如果是左括号就压入操作符栈 e.如果是右括号,则把与之匹配的左括号之间的运算符全部输出 f.如果是运算符就分情况执行以下操作 1).如果栈为空就直接压入 2).如果栈中有运算符,切当前运算符比栈顶运算符优先级高就压入,否则就弹出栈顶运算符 ,并一直重复1)、2)直到栈顶运算符优先级低于待处理运算符或栈为空 3).重复b直到读取完毕 B.后缀表达式求值,这个就相对简单一些了: a.初始化一个操作数栈 b.依次读取后缀表达式,遇到运算数就压进运算数栈,遇到操作符就将栈顶两个数pop出来求值 然后push进栈。一直循环执行b知道后缀表达式读取完毕,最后操作数栈顶那个数就是表达式。
下面就直接贴代码了,代码注释基本能够帮助快速读懂程序。
#include <iostream>
#include <stack>
using namespace std;
int getPriority(char c); //输入运算符返回优先级
bool isLeft(char c); //判断是否是左括号
bool isRight(char c); //判断是否是右括号
bool isOperator(char c); //判断是否是操作符(+-*/)
bool isNumber(char c); //判断是否是数字
double calculate(string postfix); //传入后缀表达式,计算值
string convertToPostfix(const string& expression); //将中缀表达式转化为后缀表达式
int main() {
stack<char> operatorStack;
string expression,postfix;
cout << "请输入要计算的表达式:"<<endl;
getline(cin,expression);
postfix = convertToPostfix(expression);
//输出结果
cout << "后缀表达式为(数字之间以#号分割)->"<<postfix << endl;
if (expression.at(expression.length()-1) == '=')
cout <<expression<<calculate(postfix)<<endl;
else
cout <<expression<<"="<<calculate(postfix)<<endl;
}
string convertToPostfix(const string& expression){
stack<char> operatorStack;
string postfix;
//依次读取输入的字符并按字符类型分别处理
for(int current = 0; current < expression.length(); current++){
char c = expression.at(current);
if(!isNumber(c) && !isOperator(c) && c !='(' && c != ')'){
cout << "请输入正确表达式!" << endl;
exit(0);
}
if(c != ' ' && c != '='){
//如果是左括号就压栈
if(isLeft(c)) {
operatorStack.push(c);
} else if (isRight(c)){ //是右括号则将和左括号之间的pop出去拼接到后缀表达式
while(!operatorStack.empty() && operatorStack.top() != '('){
postfix.append(1,operatorStack.top());
operatorStack.pop();
}
operatorStack.pop(); //最后将左括号pop
} else if(isOperator(c)){ //如果是操作符
if(current+1 < expression.length()){
if (isOperator(expression.at(current+1))) {
cout << "请输入正确的表达式";
exit(0);
}
}
if(current-1 >= 0){
if(isOperator(expression.at(current-1))){
cout << "请输入正确的表达式";
exit(0);
}
}
if(operatorStack.empty()){ //如果操作符栈为空就直接压栈
operatorStack.push(c);
} else{ //否则就将栈顶优先级低的依次出栈,直到栈为空或者,栈顶运算符优先级低于当前运算符
while(getPriority(c) <= getPriority(operatorStack.top())){
postfix.append(1,operatorStack.top());
operatorStack.pop();
if(operatorStack.empty())
break;
}
operatorStack.push(c);
}
} else { //最后如果是数字的话就直接接到后缀表达式
postfix.append(1,c); //同时为了方便后面计算后缀表达式值的时候明确多位数的起止,特在每个整数后面加一个分隔符$
if(current+1 < expression.length()){
if (!isNumber(expression.at(current+1))){
postfix.append(1,'#');//数字分隔符
}
}
}
}
}
//中缀表达式读取完毕后将运算符栈中剩下的运算符拼接到后缀表达式中
while(!operatorStack.empty()){
if(operatorStack.top() == '(' || operatorStack.top() == ')'){
cout << "左右括号不匹配,表达式错误!";
exit(0);
}
postfix.append(1,operatorStack.top());
operatorStack.pop();
}
return postfix;
}
//返回运算符优先级
int getPriority(char c){
if(c == '*' || c == '/')
return 2;
else if(c == '+' || c == '-')
return 1;
else
return 0;
}
bool isRight(char c){
if(c == ')')
return true;
else
return false;
}
bool isLeft(char c){
if(c == '(')
return true;
else
return false;
}
bool isOperator(char c){
if(c == '*' || c == '/' || c == '+' ||c == '-')
return true;
else
return false;
}
double calculate(string postfix){
stack<double> result;
char c;
for (int i = 0; i < postfix.length();i++) {
c = postfix.at(i);
if (isOperator(c)) {
double a = result.top();
result.pop();
double b = result.top();
result.pop();
double temp;
switch (c) {
case '+' :
temp = b + a;
break;
case '-' :
temp = b - a;
break;
case '/' :
if(a == 0){
cout << "除零错误!";
exit(0);
}
temp = b / a;
break;
case '*' :
temp = b * a;
default:
break;
}
result.push(temp);
} else if(isNumber(c)){
double num = c - '0';
while(isNumber(postfix.at(i+1))){
num = num*10+ (postfix.at(i+1) - '0');
i++;
}
result.push(num);
}
}
return result.top();
}
bool isNumber(char c){
if(c>='0'&& c<='9')
return true;
else
return false;
}
当然代码中加入了一些判别表达式错误的片段,比如左右括号不匹配,或是除数为零,以及为了支持多位数,特意在每个
数结束处加一个#号方便后缀表达式计算值时识别,相关代码段如下:
postfix.append(1,c); //同时为了方便后面计算后缀表达式值的时候明确多位数的起止,特在每个整数后面加一个分隔符# if(current+1 < expression.length()){
if (!isNumber(expression.at(current+1))){
postfix.append(1,'#');//数字分隔符
}
}
#