C++编写带有符号优先级和括号的四则运算计算器(带解析)

写在最前面:想要实现带有符号优先级的计算器,比较常用的方法是将中缀表达式转化为后缀表达式进行运算。所谓的中缀表达式就是我们平时写的计算式,例如1+2,(2+3)3之类的,而后缀表达式则是把运算符放在运算数字时候的表达方式。

后缀表达式

定义:不包括括号,运算符放在两个运算数之后,计算顺序按照严格的从左到右,不考虑符号的优先级。
例如:我们吧1+2+3转化为后缀表达式应该是12+3+。计算时先算1+2=3,后缀表达式变为33+,再计算3+3=6即为得数。

算法思路

我用了两个栈,一个数字栈,一个符号栈,顾名思义,数字栈用来存操作数,符号栈用来存运算符。这里提出符号优先级的概念,之所以*号和+号同时存在的时候要先算*,就是因为乘号的优先级要高于加号。
这里将主要算法分为几部分:

  • 如果输入的是数字就直接压入数字栈
  • 如果输入的是左括号“(”,就直接压入符号栈,我们认为左括号是优先级最低的。
  • 如果输入的是右括号“)”,就向前寻找左括号,直至将括号中间的所有符号全部弹出运算。
  • 如果输入的是“+”,“-”,就要从符号栈栈顶开始,把所有优先级大于等于“+”“-”的符号弹出进行运算。
  • 如果输入的是“*”“/”,就看符号栈栈顶是否是优先级等于“*”“/”,如果是的话则需要弹出运算。
    这些步骤你都可以手算一下看看得数是否正确,很容易验算。

图片来自https://www.cnblogs.com/GC-hahaha/p/9457720.html

值得注意的细节

  • 目前我这个程序只能对整数进行运算,无法对浮点数进行运算,后续可能会改进
  • 除法可能会产生小数,我这里做的粗精度处理,直接保留为int型
  • 对第一位是负数的应该进行特殊处理
  • 对除数是0的应该进行特殊处理

代码中所有栈我都用的C++STL标准库中的stack容器进行处理,相对手写的栈便捷许多,如果对stack容器不了解,可以移步C++中STL标准库——stack

代码实现

#include<stdio.h>
#include<stdlib.h>
#include<stack>
#include<iostream>
#include<string.h>
using namespace std;
stack<int> q1;//数字栈
stack<char> q2;//符号栈
int flag=0;//用来判断第一位是‘-’的情况
int flag2=0;//用来判断第一位是‘-’的情况
int flag1=0;//用来判断除数是0的情况
//取出数字栈顶两个数字进行s运算函数,需要注意!因为我们需要对数字栈进行入
//栈出栈操作,改变了数字栈的结构,所以我们需要在栈名前加“&”
void calculate(stack<int> &q1,char s)
{
	int x,y,z;
	switch(s)
	{
	case '+':
		{
		x=q1.top();
		q1.pop();
		y=q1.top();
		q1.pop();
		z=x+y;
		q1.push(z);
		break;
		}
	case '-':
		{
		x=q1.top();q1.pop();
		y=q1.top();q1.pop();
		z=y-x;
		q1.push(z);
		break;
		}
	case '*':
		{
		x=q1.top();q1.pop();
		y=q1.top();q1.pop();
		z=x*y;
		q1.push(z);
		break;
		}
	case '/':
		{
		x=q1.top();q1.pop();
		y=q1.top();q1.pop();
		if(x==0)
		{
			flag1=1;
			break;
		}
		z=y/x;
		q1.push(z);
		break;
		}
	}
	
}
//用数字来表示符号优先级
int fuhao(char s)
{
	if(s=='+'||s=='-')
		return 1;
	if(s=='*'||s=='/')
		return 2;
	if(s=='('||s==')')
		return 3;
	if(s=='#')
		return -1;
}
//对两个栈进行入栈出栈以及计算的函数
void function(char a[100])
{
	q2.push('#');//在符号栈先入一个“#”,防止后序找栈顶为空的时候发生异常
	int len=strlen(a);
	if(a[0]=='-')//如果第一个数字是负号的情况,要单独考虑
	{
		flag2=1;
		a[0]='0';
	}
	for(int i=0;i<len;i++)//主循环
	{
		if(a[i]=='(')
		{
			q2.push(a[i]);
		}
		else if(a[i]==')')
		{
			while(q2.top()!='(')
			{
				calculate(q1,q2.top());
				q2.pop();
			}
			q2.pop();
	
		}
		else if(a[i]>='0'&&a[i]<='9')
		{
			int num=0;
			//数字不一定只有一位,如果是多位数字要进行处理
			while(a[i]>='0'&&a[i]<='9')
			{
				num*=10;
				num+=(a[i]-'0');
				i++;
			}
			i--;
			if(flag2==1&&flag==0)//对第一位是负数的单独处理
				num*=-1;
			q1.push(num);
			flag=1;
		}
		else
		{
			if(a[i]=='+'||a[i]=='-')
			{
				if((fuhao(q2.top())>=fuhao(a[i]))&&q2.top()!='(')
				{
					while(fuhao(q2.top())>=fuhao(a[i])&&q2.top()!='(')
					{
						calculate(q1,q2.top());
						q2.pop();
						
					}
					q2.push(a[i]);
				}
				else
				{
					q2.push(a[i]);
					
				}
			}
			else if(a[i]=='*'||a[i]=='/')
			{
				if(fuhao(q2.top())==fuhao(a[i]))
				{
					calculate(q1,q2.top());
					if(flag1==1)
					{
						printf("error");
						return;
					}
					q2.pop();
					q2.push(a[i]);
					
				}
				else
				{
					q2.push(a[i]);
				}
			}
		}
	}
	//对栈中剩余数字进行处理,当字符栈空了自然运算就结束了
	while(q2.top()!= '#')
	{
	calculate(q1,q2.top());
	if(flag1==1)
	{
		printf("error");
		return;
	}
	q2.pop();
	}
	printf("%d",q1.top());
	
}
int main()//主函数
{
	char a[100];
	scanf_s("%s",a,100);
	function(a);
	return 0;
}

发布了30 篇原创文章 · 获赞 24 · 访问量 5178

猜你喜欢

转载自blog.csdn.net/weixin_45939019/article/details/104135968