实验目的:
利用“栈”完成一定程度的四则混合运算,四则运算表达式应以字符串形式读入。该段程序要实现的基本功能是实现“十以内的加减乘除运算”,在实现四则运算的简单功能后,可以考虑让表达式的第一项为负数,还可以考虑括号、乘方运算,同时将数值范围从十以内的整数扩展到有理数,通过该计算器程序的编写更好的理解与运用栈。
实验思路:
样例:
① 输入:-3.14+2*15-7^2+(12*3)
输出:13.860
②输入:-77+54*3^2-(19+3*5)
输出:375.000
③输入:79/4+51*(4.5*21+14^3)
输出:144783.250
实验代码:
/*
基础要求:以字符串形式输入一个包含加减乘除等运算符号的四则混合运算表达,
利用栈计算该表达式的值,表达式中的数值在0-9之间。
进阶:字符串中的一个字符为负号,运算符中增加括号、乘方等运算符,
表达式中的数值大于等于10,表达式中的数值为小数
范例:
①21*(5-17)+6^2
A:-216
*/
#include<stdlib.h>
#include<stdio.h>
#include <iostream>
#include <string>
#include <ctype.h>
#include <set>
#include <queue>//c++队列
#include <stack>// C++栈
#include <map>//C++中关联容器map ,本段代码中使用insert、find、empty函数
#include <math.h>//乘方运算中调用pow()
using namespace std;
//判断是否为操作符,操作符——true;否则——false;
bool is_operator(char ch) {
set<char> operator_set;
operator_set.insert('+');
operator_set.insert('-');
operator_set.insert('*');
operator_set.insert('/');
operator_set.insert('%');
operator_set.insert('^');
return operator_set.find(ch) != operator_set.end();
}
// 比较两个操作符的优先级
int compare_priority(char a, char b) {
map<char, int> operator_priority;
operator_priority.insert(make_pair('+', 1));
operator_priority.insert(make_pair('-', 1));
operator_priority.insert(make_pair('*', 2));
operator_priority.insert(make_pair('/', 2));
operator_priority.insert(make_pair('%', 2));
operator_priority.insert(make_pair('^', 3));
return operator_priority[a]-operator_priority[b];
}
//处理一元操作符 '+'和'-'
string preprocess(const string infix) {
string result = infix;
set<char> valid_char_set;
for(int i=0; i<=9; i++) {
valid_char_set.insert(i+'0');
}
valid_char_set.insert('+');
valid_char_set.insert('-');
valid_char_set.insert('*');
valid_char_set.insert('/');
valid_char_set.insert('%');
valid_char_set.insert('^');
valid_char_set.insert('(');
valid_char_set.insert(')');
valid_char_set.insert('.');//小数点
for(int i=0; i<result.size(); i++) {
//如果字符不在valid_char_set,说明有不能处理的字符,结束程序
if(valid_char_set.find(result[i]) == valid_char_set.end()) {
printf("存在非法字符!!!");
exit(-1);}
}
//处理一元操作符
for(int i=0; i<result.size(); i++) {
char temp = result[i];
if(temp != '+' && temp != '-') {
continue;
}
if(i==0) result.insert(i, 1, 0+'0');
else if(i-1>=0 && !isdigit(result[i-1]) && result[i-1]!=')') { //一元+-,紧跟着其他符号后面
result.insert(i, "(0");
int j = i+3;
int bracket_count=0;//如果有括号,应包含括号
for(; j<result.size(); j++) {
if(isdigit(result[j]) || result[j]=='.') continue;
else if(result[j]=='(') ++bracket_count;
else if(result[j]==')'){
if((--bracket_count) == 0)break;
else if(bracket_count==0)break;}
}
i = j;
result.insert(j, ")");
}
}
return result;
}
//中缀表达式--后缀表达式
queue<string> infix_to_post(string infix) {
queue<string> postfix;//后缀表达式队列
stack<char> operator_stack;//转换过程中,用来存储操作符的栈
set<char> valid_operand_set;//操作数中的字符
for(int i=0; i<=9; i++) {
valid_operand_set.insert(i+'0');
}
valid_operand_set.insert('.');
for(int i=0; i<infix.size(); i++) {
char ch = infix[i];
if(infix[i]=='(') {//左括号
operator_stack.push(infix[i]);
} else if(infix[i]==')') {//右括号
while(!operator_stack.empty() && operator_stack.top()!='(') {
postfix.push(string(1, operator_stack.top()));
operator_stack.pop();
}
operator_stack.pop();//将"("出栈
} else if(is_operator(infix[i]) == true) { //是操作符(不包含 左、右括号)
if(operator_stack.empty()) { //操作符栈为空
operator_stack.push(infix[i]);
continue;
}
//操作符栈非空
char top_stack = operator_stack.top();
//将栈中'较高和相等'优先级的操作符放到 后缀表达式中。
//终止条件为:当前操作符>栈顶操作符优先级,或优先级相等、但栈顶操作符的结合性是“从右向左”。
while(compare_priority(infix[i], top_stack)<=0) {
//优先级相等,但栈顶操作符结合性为从右向左,这里特指'^'
if(compare_priority(infix[i], top_stack)==0 && infix[i]=='^') { //因为'^'的结合性从右向左,所以单独处理
break;
}
//当前操作符<=栈顶操作符优先级,当前操作符结合性为从左到右
postfix.push(string(1, top_stack));
operator_stack.pop();
if(!operator_stack.empty()) {
top_stack = operator_stack.top();
} else break;
}
//将当前操作符入栈
operator_stack.push(infix[i]);
} else {//操作数
string current_operator;
int j=i;
while(valid_operand_set.find(infix[j]) != valid_operand_set.end()) {
current_operator += infix[j];
++j;
}
postfix.push(current_operator);
i=j-1;//因为for循环,每次都会执行i++
}
queue<string> temp_queue = postfix;
while(temp_queue.size()>0) {
temp_queue.front();
temp_queue.pop();
}
}
//最后将栈中内容全部取出来
while(!operator_stack.empty()) {
postfix.push(string(1, operator_stack.top()));
operator_stack.pop();
}
return postfix;
}
//计算两个操作数
double calculate_two(double a, double b, string operand) {
double result;
if(operand == "+") {
result = a+b;
} else if(operand == "-") {
result = a-b;
} else if(operand == "*") {
result = a*b;
} else if(operand == "/") {
if(b==0) {
exit(-1);
}
result = a/b;
} else if(operand == "%") {
result = (static_cast<int>(a)) % (static_cast<int>(b));
} else if(operand == "^") {
result = pow(a, b);
}
return result;
}
//对后缀表达式,进行计算
double calculate_post(queue<string>& post) {
stack <double> result_stack;
while(!post.empty()) {
string temp = post.front();
post.pop();
if(is_operator(temp[0])) { //是操作符
if(result_stack.size()<2) {
exit(-1);
}
double operand2 = result_stack.top();//从栈中取出两个元素
result_stack.pop();
double operand1 = result_stack.top();
result_stack.pop();
double m = calculate_two(operand1, operand2, temp);//计算并将结果压入栈中
result_stack.push(m);
} else { //操作数
double temp_operand = atof(temp.c_str());
result_stack.push(temp_operand);
}
}
return result_stack.top();
}
int main(int argc, char **argv) {
string infix;
getline(cin, infix);//输入表达式
string result_infix = preprocess(infix);//处理一元操作符:‘+’‘-’
queue<string> result_post = infix_to_post(result_infix);//将表达式转换为计算机易于理解的后缀表达式
queue<string> temp = result_post;
while(!temp.empty()) {
temp.pop();
}//判断是否栈空,若非空则弹出栈顶元素
double result = calculate_post(result_post);//对后缀表达式计算并将结果返回给result
printf("计算结果为:%.3f",result);//输出结果
return 0;
}