计算机是如何计算四则运算表达式的?

welcome
✒️博主介绍:博主大一智能制造在读,热爱C/C++,会不定期更新系统、语法、算法、硬件的相关博客,浅浅期待下一次更新吧!
✈️算法专栏:算法与数据结构
博客制作不易,点赞+⭐收藏+➕关注

文章目录

  • 引言
  • 中缀表达式
  • 后缀表达式
  • 中缀转后缀
  • 总结

引言

四则运算在我们的生活中无处不在,当出去买东西的时候,结账时收银员拿着计算器对我们买的东西进行计算的时候就进行了四则运算,在我们还是小学的时候,数学作业当中也充斥着大量的四则运算,这些表达式对于我们往往是可以很快得出结果的,因为我们清楚的知道表达式当中运算符的优先级,如括号内部优先计算,乘除优先计算,可是计算机如何得知这些?它知道这些字符的优先级吗?如果不知道它是如何去计算的呢?

中缀表达式

我们平时用的标准的四则运算表达式就是中缀表达式,如:3×(4+7)+2÷10,这种表达式对于我们而言是很轻松就能看懂的,那计算机可以吗?从计算机的角度来看或许并不可以,计算机如何去识别优先级?或者说我们写的程序如何去计算?如果没有括号的出现是可以实现的,但是很麻烦,或者说我们的水平无法实现,那计算机如何进行四则计算?通过观察可以发现,括号是成双成对的出现的,则有左括号一定就会出现右括号,那利用栈就可以将括号问题解决,同时利用栈也可以计算出最终结果,但是这时是需要两个栈的,那有没有办法只用一个栈解决呢?这里就可以使用后缀表达式来解决。

后缀表达式

后缀表达式,又称逆波兰表达式,是由波兰逻辑学家Jan Lukasiewicz发明的,它是一种不需要括号的表达式,如:3 4 7 + * 2 10 / +就是上面中缀表达式例子的的后缀表达式,这时的后缀表达式就可以直接用一个栈来处理,如3 4 7 + * 2 10 / +,它用栈进行计算的过程如下:

  1. 3 4 7 入栈,因为前三个数字是没有符号的,这时栈顶元素是7,下一个元素是4。

  2. 接下来遇到第一个符号+,这时候取出栈最上面的两个元素7和4,进行相加操作,得到11,然后入栈,这时栈内元素有3 11。

  3. 接下来接着遇到符号*,在计算机中*表示相乘,这时取出栈最上面的两个元素11和3进行相乘,得到33,将33入栈,栈内元素变成33。

  4. 接下来是两个数2和10,将它们两个入栈。

  5. 接着是/,在计算机中/表示相除,取出栈最上面两个元素10和2,相除得5,再将5入栈,下一个是符号+,将栈内最上面两个元素取出,相加得38,这个时候表达式结束,结果为38。

int posnota(string str)
{
	stack sum;
	while (!str.empty())
	{
		if (str[0] == ' ') str.erase(0, 1);//当有空格的时候对空格进行删除操作
		if(str[0] <= '9' && str[0] >= '0')//遇到这个区间的数一定是数字
		{
			string tmp;
			while (str[0] != ' ')//遇到下一个空格的时候证明该数结束
			{
				tmp += str[0];
				str.erase(0, 1);
			}
			sum.push(stoi(tmp));
		}
		if (str[0] == '+')
		{
			str.erase(0, 1);
			int x = sum.top();
			sum.pop();
			int y = sum.top();
			sum.pop();
			int z = x + y;
			sum.push(z);
		}
		if (str[0] == '-')
		{
			str.erase(0, 1);
			int x = sum.top();
			sum.pop();
			int y = sum.top();
			sum.pop();
			int z = x - y;
			sum.push(z);
		}
		if (str[0] == '*')
		{
			str.erase(0, 1);
			int x = sum.top();
			sum.pop();
			int y = sum.top();
			sum.pop();
			int z = x * y;
			sum.push(z);
		}
		if (str[0] == '/')
		{
			str.erase(0, 1);
			int x = sum.top();
			sum.pop();
			int y = sum.top();
			sum.pop();
			int z = x / y;
			sum.push(z);
		}
	}
	return sum.top();
}

在这里插入图片描述

运行结果是正常的,但是我们在日常生活中见到的都是中缀表达式,我们如何去得知后缀表达式?

中缀转后缀

中缀表达式是可以转成后缀表达式的,如何去转换呢?拿例子3*(4+7)+2/10来进行解释:

  1. 开始是数字3,直接将其输出,接下来遇到了*号,这时候栈内没有任何元素,将*号入栈。
  2. 接下来遇到了(,左括号的优先级比*号高,则入栈,并且有(,一定会出现匹配的右括号,当遇到右括号的时候,可以将左括号上面的元素全都出去。
  3. 接下来是数字4,直接输出,然后遇到了+号,还没有遇到),将+号入栈,栈内元素现在为+ ( *,接下来是数字7,输出。
  4. 遇到了),开始出栈,先是+,接着是(,匹配成一对括号,结束出栈。
  5. 遇到+,+优先级比栈顶元素*号低,这个时候将栈内元素(没有符号不高于+的优先级)全部出栈,在将+入栈。
  6. 遇到数字2,输出,接着是/号,优先级高于栈顶元素+,入栈。
  7. 遇到数字10,输出,表达式结束,将栈内全部元素输出。
int p[4] = {0, 0, 1, 1};
string o = "+-*/";
bool tf;

string infix_to_pos(string& str)
{
	stack sym;
	string tmp;
	tmp.erase(0, 1);
	while (!str.empty())
	{
		while (str[0] >= '0' && str[0] <= '9')
		{
			tmp += str[0];
			str.erase(0, 1);
		}
		tmp += ' ';
		if (str[0] == ')')
		{
			while (!(sym.top() == '('))//遇到右括号则栈内一定会出现左括号
			{
				tmp += sym.top();
				sym.pop();
				tmp += ' ';
			}
			sym.pop();
			str.erase(0, 1);
		}
		//当当前一定是符号的时候,只要栈为空,或者当前符号优先级高于栈顶元素,则就将符号入栈,或者当栈顶元素为(时候直接入栈
		if ((str[0] <= '0' || str[0] >= '9') && (sym.empty() ||tf|| p[o.find(str[0])] > p[o.find(sym.top())]))
		{
			tf = false;
			sym.push(str[0]);
			str.erase(0, 1);
		}
		//当遇到左括号的时候入栈,并且打上记号为true,使其他符号不与(比优先级,直接进去入栈
		if (str[0] == '(')
		{
			sym.push(str[0]);
			str.erase(0, 1);
			tf = true;
		}
		//当前符号的优先级是不高于栈顶元素的,就出栈顶元素,并且栈不能为空
		while ((str[0] <= '0' || str[0] >= '9') && !sym.empty() && p[o.find(str[0])] <= p[o.find(sym.top())])
		{
			tmp += sym.top();
			sym.pop();
			tmp += ' ';
		}
	}
	return tmp;
}

在这里插入图片描述

通过中缀转后缀,在让程序利用后缀去计算得出的答案是正确的,表明当前程序无问题。

总结

对于计算机而言,日常生活中的中缀表达式是比较难以理解的,而逆波兰表达式可以很好的去解决这一问题,同时中缀表达式可以转变成逆波兰表达式。

专栏:算法与数据结构
都看到这里了,留下你们的点赞+⭐收藏+评论吧

你可能感兴趣的:(算法与数据结构,c++,算法,c语言,数据结构)