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

 

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

(希望可以帮到有需要的人~~)

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值