《利用栈实现含浮点数的算术表达式的计算》

来源:互联网 发布:工程预算软件下载 编辑:程序博客网 时间:2024/06/15 17:14


1、基本思路:

先将算术表达式(中缀式)读入到string对象中,再将其经过相关操作解析并转换成后缀表达式(存放在一条链表中),最后才(遍历该链表)对该表达式进行运算。


2、如何支持浮点数的运算:
a、使用atof()函数,它是C语言标准库中的一个字符串处理函数,功能是把字符串转换成浮点数,其头文件为<stdlib.h>,该函数名是 "ASCII to floating point numbers" 的缩写。
语法格式为:double atof(const char *nptr)。
b、说明:atof()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。


3、具体实现代码(含详细注释,不懂的地方可以留言):


#include<iostream>#include<stack>#include<stdlib.h>#include<string>using namespace std;//使用结点Node类来存储操作数或运算符struct Node{bool isOperand; //判断结点里存储的是否为操作数double operand;char Operator;Node* next;Node(bool isOpd = false, double opd = 0.0, char Opr = ' '){isOperand = isOpd;operand = opd;Operator = Opr;next = nullptr;}};//定义一个Calculator类来存放计算后缀式算术表达式时所需的基本操作class Calculator{public:Calculator() {}double runPostfixExpression(Node* head); //执行对后缀式算术表达式的计算private:stack<double> st;  //存放操作数(double类型)的栈void addOperand(double value);  //操作数进栈bool get2Operands(double& left, double& right); //从栈中取出(退出)两个操作数bool doOperator(char op); //使用该运算符进行一次基本算术运算};double Calculator::runPostfixExpression(Node* head){double newOperand;while (head != nullptr){if (head->isOperand) addOperand(head->operand); //是操作数,直接进栈else doOperator(head->Operator);  //是运算符,执行基本算术运算head = head->next;}newOperand = st.top();return newOperand;}void Calculator::addOperand(double Operand){st.push(Operand);}bool Calculator::get2Operands(double& leftOperand, double& rightOperand){if (st.empty()){cerr << "缺少右操作数!" << endl;return false;}rightOperand = st.top();st.pop();if (st.empty()){cerr << "缺少左操作数!" << endl;return false;}leftOperand = st.top();st.pop();return true;}bool Calculator::doOperator(char op){double left, right, value;bool result = get2Operands(left, right);if (result){switch (op){case '+':value = left + right;st.push(value);break;case '-':value = left - right;st.push(value);break;case '*':value = left * right;st.push(value);break;case '/':if (right == 0.0){cerr << "Divided by 0!" << endl;return false;}else{value = left / right;st.push(value);}break;}return true;}else return false;}//isp(in stack priority)为该算术运算符栈内优先级int isp(char c){switch (c){case '#': return 0;case '(': return 1;case '*':case'/': return 5;case '+':case '-': return 3;case ')': return 6;default: return -1;}}//icp(in coming priority)为该算术运算符栈外优先级int icp(char c){switch (c){case '#': return 0;case '(': return 6;case '*':case'/': return 4;case '+':case '-': return 2;case ')': return 1;default: return -1;}}Node* infixToPostfix(string str){double operand;//给中缀算术表达式str末尾添加个字符'#',以便利于后面栈内外运算符优先级比较时出栈的处理str = str + '#';Node* head, *current;stack <char> st;char charInStack; //存放在栈st中的操作数或运算符int i = 0;while (i < str.size()){if (isdigit(str[i])) //如果是操作数,则处理(取浮点数)后便可直接存入Node对象中{if (i == 0)  //处理中缀表达式str中开头的操作数{//读取该操作数(double类型)并存入Node对象中operand = atof(&str[i]);current = new Node(true, operand, 0.0);head = current; //建立表头结点}else  //处理中缀表达式str中的其他操作数{//读取该操作数(double类型)并存入Node对象中operand = atof(&str[i]);current->next = new Node(true, operand, 0.0);current = current->next;}while (isdigit(str[i]) || str[i] == '.') //过滤掉(跳过)string转换double时已被使用的那些char字符{i++;}}else  //如果是运算符,则进行一系列(栈内外)运算符优先级的比较并结合相关的入栈出栈操作,适时将运算符存入Node对象{if (st.empty()){if (i == str.size() - 1) break;  //若此时栈空且str已被扫描完,则结束循环else //若此时栈空且str还未被扫描完,则继续将当前扫描到的运算符进栈{st.push(str[i]);i++;}}else{charInStack = st.top();//栈内运算符优先级<栈外运算符优先级,则将栈外运算符str[i]直接进栈if (isp(charInStack) < icp(str[i])){st.push(str[i]);i++;}//栈内运算符优先级>栈外运算符优先级,则将栈顶的运算符出栈并将其存入Node对象中else if (isp(charInStack) > icp(str[i])){charInStack = st.top();st.pop();current->next = new Node(false, 0.0, charInStack);current = current->next;}//栈内运算符优先级=栈外运算符优先级,此时只有一种可能,即栈内的'('/')'的优先级与栈外的')'/'('优先级相等且均为1/6,//即匹配情况为“()”或“)(”,此时直接将栈内的运算符出栈,丢弃当前所扫描的str[i] 运算符,继续扫描下一个运算符else{st.pop();i++;}}}}return head;}int main(void){string expression;while (1){Calculator c;cout << "请输入算术表达式:" << endl;cin >> expression;cout << "Result = " << c.runPostfixExpression(infixToPostfix(expression)) << endl;}return 0;}



原创粉丝点击