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;
}
顺便附上项目源码,支持开源精神,欢迎star、fork:
https://github.com/Yuziquan/CalculateArithmeticExpressionForFloatingpoint
(希望可以帮到有需要的人~~)