表达式求值问题-双栈模板化实现

文章介绍了如何实现一个简单的计算器,重点讨论了解决运算符优先级问题的方法,通过使用栈来存储数字和运算符,当遇到优先级较低的运算符时进行计算。文章提供了C++代码示例,展示了一个基于栈的表达式计算模板,并强调了代码的可复用性和可扩展性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        好久不见,真的很久都没有更新博客了,最近很多事情,所以比较忙碌,没有时间每天都学算法,但是我会挤时间尽量做到,每两三天就更新博客,我会努力的,加油~

    前言:计算器都见过吧,我们今天要讲的就是类似于计算器计算数据的简单实现,我们需要注意一些问题,比如运算符优先级,运算顺序等等问题,话不多说,冲冲冲!!!

目录

1.问题引入

2.问题分析及解决方法

如何设计优先级问题?

设计计算函数和启动计算条件

完整代码(可做为表达式计算模板使用)

3.金句频道


1.问题引入

2.问题分析及解决方法

       首先,我们先来看一下整体思路:对于一个表达式,我们会读入括号,运算符和数字三种字符,我们需要将这些字符区分开再进行计算,为了保证运算的正确性,由运算符带来的优先级问题是我们解决这个问题的关键,解决了运算符优先级问题,我们就可以将运算符和数字分别存入一个栈中,用读取到' ) '和读取到优先级比已经保存在栈内的运算符来作为启动计算的条件(读到右括号,我们就可以将整个括号内部的部分算出来,再将算得结果压入保存数字的栈中用于后续的计算,而对于读取到优先级低的运算符,因为我们以栈存储数据,导致我们在计算的时候就会按逆序进行计算,所以,我们每次读取到一个运算符优先级低于栈顶的字符,都要先将栈内的运算符优先级高的运算符的结果算出,从而不影响运算顺序),最后,我们的运算符栈内如果还剩下元素,直接计算即可。

如何设计优先级问题?

       这里方法就有很多了,既可以用一个专门的函数来实现,也可以用STL的map键值来实现等等,这里我们采用第二种方法,该方法比较简单且代码易扩展,方便后序添加运算符。

unordered_map<char, int> p{ {'+',1},{'-',1},{'*',2},{'/',2} };//用来表示运算符的优先级,数字越大表示运算优先级越高

设计计算函数和启动计算条件

//计算函数
void f()
{
	//这里需要注意,我们的栈内保存的待运算数字和运算顺序是反着的,会影响减法和除法的计算
	auto b = num.top(); num.pop();
	auto a = num.top(); num.pop();
	auto c = op.top(); op.pop();
	if (c == '+')
		num.push(a + b);
	else if (c == '-')
		num.push(a - b);
	else if (c == '*')
		num.push(a * b);
	else if (c == '/')
		num.push(a / b);
	//如果想要再拓展其他运算,可在此处继续写下去

}

//计算启动条件
else if (s[i] == '(')//如果是左括号,直接入栈等待右括号到来再计算
			op.push(s[i]);
		else if (s[i] == ')')//右括号,准备开始计算结果
		{
			while (op.top() != '(') f();//做括号内的计算
			op.pop();//弹出左括号
		}
		else
		{
			while (!op.empty() && p[op.top()] >= p[s[i]]) f();//如果遇到优先级比前面已经入栈的运算符的优先极低的,则要先解决栈内的计算再将该优先级高的字符入栈
			op.push(s[i]);
		}

完整代码(可做为表达式计算模板使用)

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
const int maxn = 1e5 + 10;

stack<int >num;
stack<char> op;//运算符

unordered_map<char, int> p{ {'+',1},{'-',1},{'*',2},{'/',2} };//用来表示运算符的优先级,数字越大表示运算优先级越高

void f()
{
	//这里需要注意,我们的栈内保存的待运算数字和运算顺序是反着的,会影响减法和除法的计算
	auto b = num.top(); num.pop();
	auto a = num.top(); num.pop();
	auto c = op.top(); op.pop();
	if (c == '+')
		num.push(a + b);
	else if (c == '-')
		num.push(a - b);
	else if (c == '*')
		num.push(a * b);
	else if (c == '/')
		num.push(a / b);
	//如果想要再拓展其他运算,可在此处继续写下去

}
int main()
{
	string s;
	cin >> s;
	for (int i = 0; i < s.size(); i++)
	{
		if (isdigit(s[i]))//注意,这里需要注意10以上的数,不能只看一个字符就完了
		{
			int j = i;
			int temp = 0;
			while (j < s.size() && isdigit(s[j]))
			{
				temp = temp * 10 + s[j++] - '0';
			}
			i = j-1;//j在退出循环之前已经自增了,所以要减去
			num.push(temp);
		}
		else if (s[i] == '(')//如果是左括号,直接入栈等待右括号到来再计算
			op.push(s[i]);
		else if (s[i] == ')')//右括号,准备开始计算结果
		{
			while (op.top() != '(') f();//做括号内的计算
			op.pop();//弹出左括号
		}
		else
		{
			while (!op.empty() && p[op.top()] >= p[s[i]]) f();//如果遇到优先级比前面已经入栈的运算符的优先极低的,则要先解决栈内的计算再将该优先级高的字符入栈
			op.push(s[i]);
		}
	}
	//如果最后栈内还剩下字符,直接计算即可
	while (op.size()) f();
	printf("%d\n", num.top());

	return 0;
}

     我们这里将计算函数和优先级单独设计,目的就是增加代码的可复用性,main函数内部没有涉及运算符的种类和其他的特殊处理,将特异性的功能封装成函数方便后序增添功能。

3.金句频道

       常常熬不住的时候也想找个靠山靠一下,可怎么找都会发现,有的山长满荆棘,有的山上全是野兽,所以你应该是自己的那座山。过度的依赖总会失掉自我,变得被动,不要总是整天“大佬带我飞”,让自己强起来才是一芳永逸的事。要相信每一次普通的改变,都可能改变原本的普通。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值