模拟表达式运算(加减乘除,负数,带括号)

模拟表达式运算(加减乘除,负数,带括号)
要模拟表达式运算需要目标不同表达式之间的转换关系.
可以参考我的另一篇文章(中后缀表达式转换)
由于水平问题(自己写的总有bug,而且又长又繁琐),所以参考代码选取网上的优秀代码,
但网上的模拟表达式运算要么解释不清楚,要么代码不够完善.
所以我修改了一下网上代码,使其更简单,更完善.
这份代码用数组来表达堆栈.

运算数与运算符用同一个变量p表示栈顶下标.
因为双目运算符是两个元素进行运算,返回一个运算. n个运算数,则有n-1个双目运算符.(只包括双目运算符)
一个运算符对应它右边的运算数.(左括号用0对应,但0不参与运算,具体过程看下面代码)
最后返回1个最终结果.
按步骤分割程序:
(具体解释和细节都添加到注释中)
数据声明(全部采用全局变量):

int number[101];//储存运算数
char symbol[101];//储存运算符
char s[101];//储存字符串 
int i=0;//用来遍历字符串 
int p=1;//表达栈顶下标,初始化1是为了防止下标越界

入栈操作:

void push()//入栈 
{
	symbol[++p]=s[i];
	//先增加p值然后将运算符置于栈顶.
}

出栈操作:(每输出一个就进行一次运算,就无需储存输出后的运算符)

void pop()//出栈,并顺带完成相应的运算 
{//将number[p](栈顶)与number[p-1]进行运算,并将结果储存在number[p-1]; 
	p--;//出栈后,栈顶下标-1;
	//number[p]是新的栈顶元素
	if(symbol[p+1]=='+')//已经弹出的运算符
	{
		number[p]+=number[p+1];//运算结果
	}else if(symbol[p+1]=='-')
	{
		number[p]-=number[p+1];
	}else if(symbol[p+1]=='*')
	{
		number[p]*=number[p+1];
	}else if(symbol[p+1]=='/')
	{
		number[p]/=number[p+1];
	}
}

返回运算符优先级:(可以加上其它优先级的运算符)

int cmp(char a)//返回运算符优先级
{
	if(a=='*'||a=='/')
	{
		return 2;
	}else if(a=='+'||a=='-')
	{
		return 1;
	}else if(a=='(')//入栈的括号优先级最低
	{
		return 0;
	}
	return 0;
} 

通过优先级比较判断出栈还是入栈:

int can()
{
	if(cmp(s[i])<=cmp(symbol[p]))//当栈顶运算符优先级大于等于比较运算符时进行出栈 
	{
		return 1; 
	}
	return 0;
}

转换成数字:(可以用辅助字符数组记录数字,然后用atof转换,就可以处理浮点数)

		int sum=0;
		while(s[i]>='0'&&s[i]<='9')//转化数字 
		{
			sum=sum*10+s[i++]-'0';
		}
		number[p]=sum;//设为栈顶运算数(因为下一个一定是运算符),初始化为0. 

对运算符进行操作:

do{//一定进行一轮 
		if(s[i]==')')//遇到右括号,不入栈 
		{
			while(symbol[p]!='(')//不是左括号则出栈 
			pop();
			//栈顶为左括号时 
			number[--p]=number[p+1];//处理括号对应的0;
			//此时symbol[p]为'(',因为'('对于的值是没有赋值的0,所以用栈顶的值代替括号对应的值. 
	 }
	 else
	 {
	 	if(s[i]=='-'&&s[i-1]=='*'||s[i-1]=='/')//处理负数 (单目运算符) 
	 	{number[p-1]*=-1;//改成负数
	 	 i++; 
	 	 continue;
		}
	 	while(can())//一直出栈直到可以入栈 
	 	pop();
	 	push();
	 }
	 i++;
}while(i<strlen(s)&&s[i-1]==')');//判断是否有多重括号

完全代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int number[101];//储存运算数
char symbol[101];//储存运算符
char s[101];//储存字符串 
int i=0;//用来遍历字符串 
int p=1;//表达栈顶下标,初始化1是为了防止下标越界
void push()//入栈 
{
	symbol[++p]=s[i];
	//先增加p值然后将运算符置于栈顶.

}
void pop()//出栈,并顺带完成相应的运算 
{//将number[p](栈顶)与number[p-1]进行运算,并将结果储存在number[p-1]; 
	p--;//出栈后,栈顶下标-1;
	//number[p]是新的栈顶元素
	if(symbol[p+1]=='+')//已经弹出的运算符
	{
		number[p]+=number[p+1];//运算结果
	}else if(symbol[p+1]=='-')
	{
		number[p]-=number[p+1];
	}else if(symbol[p+1]=='*')
	{
		number[p]*=number[p+1];
	}else if(symbol[p+1]=='/')
	{
		number[p]/=number[p+1];
	}
}
int cmp(char a)//返回运算符优先级
{
	if(a=='*'||a=='/')
	{
		return 2;
	}else if(a=='+'||a=='-')
	{
		return 1;
	}else if(a=='(')
	{
		return 0;
	}
	return 0;
} 
int can()
{
	if(cmp(s[i])<=cmp(symbol[p]))//当栈顶运算符优先级大于等于比较运算符时进行出栈 
	{
		return 1; 
	}
	return 0;
}
int main()
{
	gets(s);
	s[strlen(s)]=')';
	symbol[p]='(';//symbol[1]是括号,防止对空栈操作,同时对应第一个数
	while(i<strlen(s))
	{
		while(s[i]=='(')//优先录入左括号 
		{
			push();
			i++;
		}
		int sum=0;
		while(s[i]>='0'&&s[i]<='9')//转化数字 
		{
			sum=sum*10+s[i++]-'0';
		}
		number[p]=sum;//设为栈顶运算数(因为下一个一定是运算符),初始化为0. 
 		do{//一定进行一轮 
				if(s[i]==')')//遇到右括号,不入栈 
				{
					while(symbol[p]!='(')//不是左括号则出栈 
					pop();
					//栈顶为左括号时 
					number[--p]=number[p+1];//处理括号对应的0;
					//此时symbol[p]为'(',因为'('对于的值是没有赋值的0,所以用栈顶的值代替括号对应的值. 
			 }
			 else
			 {
			 	if(s[i]=='-'&&s[i-1]=='*'||s[i-1]=='/')//处理负数 (单目运算符) 
			 	{number[p-1]*=-1;//改成负数
			 	 i++; 
			 	 continue;
				}
			 	while(can())//一直出栈直到可以入栈 
			 	pop();
			 	push();
			 }
			 i++;
		}while(i<strlen(s)&&s[i-1]==')');//判断是否有多重括号
	}
	cout<<number[0]<<endl; 
	return 0;
}

注意点:
1.开头就自动在首尾添上括号
2.先p++才入栈,同个p,symbo先被赋值
3.遇到左括号则将对应数值"左移".
4.number[0]是最终结果.
该代码运行流程:
案例:5+9/3
在这里插入图片描述

这段代码对于初学者来说可能很复杂,可以多调试几遍或画图来加深理解.
由于水平问题,文章中可能存在不足和错误,欢迎评论指出.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值