刷题笔记(一)栈的应用——四则运算表达式求值

0 问题描述

输入一个只包含个位数字的简单四则运算表达式字符串,计算该表达式的值
注:

  1. 表达式只含 +, -, *, /, (, ), 四则运算符
  2. 表达式数值只包含个位整数(0-9),且不会出现0作为除数的情况
  3. 要考虑加减乘除按通常四则运算规定的计算优先级
  4. 除法用整数除法,即仅保留除法运算结果的整数部分。比如8/3=2。输入表达式保证无0作为除数情况发生
  5. 输入字符串一定是符合题意合法的表达式,其中只包括数字字符和四则运算符字符,除此之外不含其它任何字符,不会出现计算溢出情况
    • 要求实现函数:
int calculate(int len,char *expStr)
//int len: 字符串长度;
//char *expStr: 表达式字符串;
//返回计算结果

一、后缀表达式

1.原理

关于解法之前在网上查过,但是都过于复杂,看的没有头绪。后来在程杰著的《大话数据结构》一书的第四章——栈的应用中看到了关于四则表达式求值的问题·,其中提到了后缀表达式,即所有的符号都是在要运算的数字后面出现。例如我们要计算

		9 + ( 3 - 1 ) × 3 + 10 ÷ 2

将其转换为后缀表达式即为

		9 3 1 - 3 × + 10 ÷ 2

那么怎样由后缀表达式求得最终运算结果呢,书中也给了详细介绍:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
具体步骤上面说的很详细,不过简而一句话就是从左到右遍历字符串,遇到数字则进栈,遇到运算符 则将栈顶两个数字取出,进行相应的运算,然后再将结果存入栈中,最后得到的就是表达式的结果

2.代码
int Solution::calculate(int len, char *expStr)
{
  string str = expStr;
  stack<int> num;            //运算的结果不止一位数 类型要用int而不是char
  int num1 = 0, num2 = 0, result = 0;  //操作数1,操作数2,结果
  for (int i = 0; i < str.length(); i++)     //遍历字符串
  {
  	if (str[i] <= '9' && str[i] >= '0')              //如果是数字则进栈
  	{
  		num.push(str[i] - '0');                      //由ASCII码转换为数字
  	}
  	else                                             //遇到运算符
  	{
  		num2 = num.top();                            //先将栈顶取出 再pop()
  		num.pop();
  		num1 = num.top();
  		num.pop();
  		switch (str[i])                             //判断运算符,并进行相应运算,结果再存入栈中
  		{
  		case '+':
  			result = num1 + num2;
  			num.push(result);
  			break;
  		case '-':
  			result = num1 - num2;
  			num.push(result);
  			break;
  		case '*':
  			result = num1 * num2;
  			num.push(result);
  			break;
  		case '/':
  			result = num1 / num2;
  			num.push(result);
  			break;
  		default:
  			break;
  		}
  	}
  }
  return result;                   //返回结果
}

二、中缀表达式转后缀表达式

对于我们常用的中缀表达式如何转换为后缀表达式,书中也给了详细的说明:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
规则:从左到右遍历中缀表达式中的每一个数字和符号,如果是数字就输出,即成为后缀表达式的一部分;如果是符号,则判断其与栈顶符号的优先级,是右括号或者优先级不高于栈顶符号,则栈顶元素依次输出并出栈,然后将当前符号进栈,直到最终输出后缀表达式为止。
代码:

string Solution::mid2suff(int len,char *expStr)
{
	string str = expStr;
	int n = 0;
	list<char> suffixExp;		//用于存放输出的后缀表达式
	list<char>::iterator it;    //用于遍历后缀表达式的list
	stack<char> tmp;            //用于符号进栈
	for (int i = 0; i < len; i++)
	{
		if (str[i] <= '9' && str[i] >= '0') //是数字就输出
		{
			suffixExp.push_back(str[i]);
		}
		else                            //如果是符号就判断该符号与栈顶符号的优先级
		{
			if (tmp.empty())            //如果是空栈 则符号直接进栈
			{
				tmp.push(str[i]); 
			}
			else                        //不是空栈 则与栈顶比较
			{
				switch (str[i])
				{
				case '+':               //如果是+- ,优先级最低 原来的栈顶先出栈 然后 + - 进栈
				case '-':
					while ((!tmp.empty()) && (tmp.top() != '('))  //'('只有遇到')'才输出
					{
						suffixExp.push_back(tmp.top());   //要先输出到后缀表达式 再出栈
						tmp.pop();
					}
					tmp.push(str[i]);     //+-进栈
					break;
				case '(':                 //遇到'('直接进栈
					tmp.push(str[i]);
					break;
				case ')':               //如果是 )  那么括号之间的符号出栈 (加入到输出)
					while (tmp.top() != '(')
					{
						suffixExp.push_back(tmp.top());
						tmp.pop();
					}
					tmp.pop();          //将 左括号 出栈  但是不加入到输出中
					break;
				case '*':
				case '/':
					if(tmp.empty())       //如果空栈  直接进栈
						tmp.push(str[i]);   
					else                    //遇到 */ 时 前面的*或者/要先出栈
					{
						while ((tmp.top() =='*')||(tmp.top() == '/'))
						{
							suffixExp.push_back(tmp.top());
							tmp.pop();
							if (tmp.empty())
								break;
						}
						tmp.push(str[i]);  // * / 进栈
					}
					break;
				default:
					break;
				}
			}
			
		}
	}
	while (!tmp.empty())   //表达式遍历结束   如果栈中还有符号则依次出栈
	{
		suffixExp.push_back(tmp.top());
		tmp.pop();
	}
	for (it = suffixExp.begin();it!=suffixExp.end();it++) // 将list转为string
	{
		str[n++] = *it;
	}
	if (n < len)    //string的末尾删除
	{
		str.erase(n);
	}
	//cout << str << endl;
	return str;
}

其中需要注意的地方:
1.如果栈区为空时 执行 pop()操作程序会出错,故在栈区有可能为空的情况下,出战之前要先判断stack.empty();
2.同样,在栈区为空时,查询栈顶数据也会出错,程序中有一段代码:

while ((!tmp.empty()) && (tmp.top() != '('))  //'('只有遇到')'才输出
{
	suffixExp.push_back(tmp.top());   //要先输出到后缀表达式 再出栈
	tmp.pop();
}

如果while的两个判断条件交换顺序,则空栈的时候该处会出错;
3.上面的规则中,“输出”指的是将栈顶元素输出到后缀表达式中,而“出栈”仅仅是将栈顶元素删除,故应先将栈顶元素放到后缀表达式中再执行出栈操作。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值