利用栈实现计算器(calculator)一:基本思路及实现

github:https://github.com/AnkangH/CSDN/blob/master/%E5%88%A9%E7%94%A8%E6%A0%88%E5%AE%9E%E7%8E%B0%E8%AE%A1%E7%AE%97%E5%99%A8/01.%E5%9F%BA%E6%9C%AC%E6%80%9D%E8%B7%AF%E5%8F%8A%E5%88%9D%E6%AD%A5%E5%8A%9F%E8%83%BD%E5%AE%9E%E7%8E%B0

1.要求

输入一个数学算术表达式,计算它的值并输出,实现科学计算器。输入为0-9数字,+ -*,以及()括号。
暂时完成了数字0-9的运算,对于大于两位的十进制数,需要将原先的char变为string,并且对字符串进行划分,来确定每个数字大小。如对于“1+2”和“11+22”,基本的运算程序相同,只是需要根据运算符和可能的括号来确定参加计算的数值是多少。

2.设计思路

2.1 改写后缀表达式

对于一个数学算术表达式,如6*(5+(2+3)*8+3),需要根据算术计算符的优先级进行划分,先计算优先级高的,其结果再参与下个计算。上述表达式为中缀记法,而后缀记法为6523+8*+3+*。可以看出后缀记法不含有括号,且计算顺序为从左到右,不需要判断优先级。
基本思路是利用栈将中缀算术表达式改写为后缀算术表达式。然后利用栈求解后缀算术表达式的结果

对于带有括号的中缀表达式,可以利用栈实现中缀表达式到后缀表达式的改写。基本思路是遍历输入字符串,对于每个字符进行判断。
如果是数字,则放到输出表达式中。
如果是运算符‘ + ’ ‘ - ’ ‘ * ’ ‘ ( ’那么根据栈顶元素判断。如当前运算符优先级>栈顶元素,当前运算符入栈。否则栈顶元素出栈,放入输出表达式,直到当前运算符优先级小于栈顶元素或栈空。
如果是运算符‘)’那么将栈顶元素放到输出表达式时,直到栈顶元素为‘(’。

   

2.2 计算后缀表达式

遍历后缀表达式,因为后缀表达式不含有括号,所有只有数字和算术运算符之分。对于后缀算术表达式,可以利用栈很容易的实现。遍历字符串“6523+8*+3+*”,非运算符入栈,遇到运算符时,取栈顶两个元素(栈顶元素和次栈顶元素)根据运算符计算结果,结果入栈。如此循环,栈顶元素即为计算结果。这里注意加法和乘法对元素的先后没有要求,但是减法对元素的先后有要求。根据后缀表达式的改写规则,a-b的减法,在后缀表达式中,a在b之前,所以计算时,在辅助栈中,a在下,b在上。

   

3.C++实现

3.1中缀表达式改写后缀表达式

string mid2back(string s)
{
	string res;
	stack st;
	int size = s.size();
	for (int i = 0; i < size; i++)
	{
		if (s[i] != '('&&s[i] != ')'&&s[i] != '+'&&s[i] != '*'&&s[i]!='-')
			res += s[i];//数字直接放入算术表达式
		if (s[i] == '(')
			st.push(s[i]);//'('左括号优先级最高 直接入栈
		if (s[i] == '+'||s[i]=='*'||s[i]=='-')//或'*' '+' '-'
		{
			if (st.empty())
				st.push(s[i]);//栈空 算术符号入栈
			else//否则根据算术符号优先级出栈
			while (1)
			{
				char temp = st.top();//栈顶算术符号
				if (priority(s[i], temp))//栈顶算术符号优先级高于当前算术符号
				{
					st.push(s[i]);//入栈
					break;//出循环
				}
				else
				{
					res += temp;//否则栈顶算术符号放入算术表达式
					st.pop();//直到当前算术符号优先级小于栈顶算术符号
					if (st.empty())//如果栈空 那么当前算术符号入栈
					{
						st.push(s[i]);
						break;//出循环
					}
				}
			}

		}
		if (s[i] == ')')//如果是右括号 
		{
			while (st.top() != '(')//算术符号出栈 直到栈顶为左括号
			{
				res += st.top();
				st.pop();
			}
			st.pop();//'('出栈 且不放入算术表达式
		}
	}
	while (!st.empty())//栈中剩余算术符号放入算术表达式
	{
		res += st.top();
		st.pop();
	}
	return res;//转换后的算术表达式
}

3.2 计算后缀表达式

int compute(string str)//根据后缀算术表达式计算值
{
	stack st;
	int size = str.size();
	for (int i = 0; i < size; i++)
	{
		if (str[i] != '+'&&str[i] != '*'&&str[i]!='-')
			st.push(str[i] - '0');//数字入栈 注意char转int
		if (str[i] == '+')//执行加法
		{
			int a = st.top();
			st.pop();
			int b = st.top();//取栈顶两元素
			st.pop();
			st.push(a + b);//加法的和入栈
		}
		if (str[i] == '*')//执行乘法
		{
			int a = st.top();
			st.pop();
			int b = st.top();//取栈顶两元素
			st.pop();
			st.push(a*b);//乘法的积入栈
		}
		if (str[i] == '-')//执行乘法
		{
			int a = st.top();
			st.pop();
			int b = st.top();//取栈顶两元素
			st.pop();
			st.push(b-a);//乘法的积入栈
		}
	}
	return st.top();//返回后缀表达式的计算结果
}

3.3 算术优先级判断

bool priority(char a, char b)
{
	//算术优先级a>b 返回true
	//加法
	if (a == '+'&&b == '+')
		return false;
	if (a == '+'&&b == '*')
		return false;
	if (a == '+'&&b == '(')
		return true;
	if (a == '+'&&b == '-')
		return false;
	//减法
	if (a == '-'&&b == '+')
		return false;
	if (a == '-'&&b == '-')
		return false;
	if (a == '-'&&b == '*')
		return true;
	if (a == '-'&&b == '(')
		return true;
	//乘法
	if (a == '*'&&b == '+')
		return true;
	if (a == '*'&&b == '-')
		return true;
	if (a == '*'&&b == '*')
		return false;
	if (a == '*'&&b == '(')
		return true;
	return false;//语法要求必有返回值
}

4.测试

#include //for cout endl
#include //for stack
#include// for string
using namespace std;
string mid2back(string);//中缀计算表达式转后缀计算表达式
int compute(string);//计算后缀表达式
bool priority(char a, char b);//辅助函数 判断两个运算符的优先级
int main()
{
	string str="6523+8*+3+*";//真实后缀表达式
	string str1 = "6*(5+(2+3)*8+3)";//中缀表达式 测试值
	string str2 = mid2back(str1);//改写的后缀表达式
	cout <<"infix: "<

你可能感兴趣的:(数据结构与算法)