C++的逆波兰表达式的求解

梦想的初衷 提交于 2019-12-04 02:09:53
逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。逆波兰结构由弗里德里希·鲍尔(Friedrich L. Bauer)和艾兹格·迪科斯彻在1960年代早期提议用于表达式求值,以利用堆栈结构和减少计算机内存访问。逆波兰记法和相应的算法由澳大利亚哲学家、计算机学家查尔斯·汉布林(Charles Hamblin)在1960年代中期扩充在1960和1970年代,逆波兰记法广泛地被用于台式计算器,因此也在普通公众(工程、商业和金融领域)中使用(百度百科)。
算法:
一、 将中缀表达式转换成后缀表达式算法:
1、从左至右扫描一中缀表达式。
2、若读取的是操作数,则判断该操作数的类型,并将该操作数存入操作数堆栈
3、若读取的是运算符
(1) 该运算符为左括号"(",则直接存入运算符堆栈。
(2) 该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。
(3) 该运算符为非括号运算符:
(a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。
(b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。
(c) 若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈。
4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。
二、逆波兰表达式求值算法:
1、循环扫描语法单元的项目。
2、如果扫描的项目是操作数,则将其压入操作数堆栈,并扫描下一个项目。
3、如果扫描的项目是一个二元运算符,则对栈的顶上两个操作数执行该运算。
4、如果扫描的项目是一个一元运算符,则对栈的最顶上操作数执行该运算。
5、将运算结果重新压入堆栈。
6、重复步骤2-5,堆栈中即为结果值。

#include <iostream>
#include <string>
#include <iterator>
#include "ChainStack.cpp"
using namespace std;
string reverseConvert(const string& inputString);//将中序表达式转换成逆波兰表达式
int calculateString(const string& inputString);//将逆波兰表达式求解
bool isNumber(const char e);//判断字符是否为数字
bool isSymbol(const char e);//判断字符是否为符号
bool checkLevel(const char c1, const char c2);//c1的运算级别小于c2;返回true;
int levelSymbol(const char c1);//返回符号的级别
 


int main()
{
	string Input = "2*(1+2/2) ";
	string Output = reverseConvert(Input);
	cout << Input << endl;
	cout << Output << endl;
	cout << "2*(1+2/2 = " << calculateString(Output) << endl;
	
	return 0;
}

int calculateString(const string& inputString)
{		
	ChainStack<char> resultStack;
	string temp = inputString;
	string::iterator i = temp.begin();
	for (; i !=temp.end(); ++i)
	{
		if (isNumber(*i))
		{
			resultStack.Push(*i);
		}
		else
		{
			char t1, t2;
			int result;
			resultStack.Pop(t1);
			resultStack.Pop(t2);
			if (*i=='+')
			{
				result = (t2 - '0') + (t1 - '0');
				resultStack.Push(result+'0');
			}
			if (*i == '-')
			{
				result = (t2 - '0') - (t1 - '0');
				resultStack.Push(result + '0');
			}
			if (*i == '*')
			{
				result = (t2 - '0') * (t1 - '0');
				resultStack.Push(result + '0');
			}
			if (*i == '/')
			{
				result = (t2 - '0') / (t1 - '0');
				resultStack.Push(result + '0');
			}
			if (*i == '%')
			{
				result = (t2 - '0') % (t1 - '0');
				resultStack.Push(result + '0');
			}
		}
	}
	char topChar;
	resultStack.GetTop(topChar);
	return topChar-'0';
}
bool isNumber(const char e)
{
	bool temp = false;
	switch (e)
	{
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		temp = true;
		break;
	default:
		break;
	}
	return temp;
}
bool isSymbol(const char e)
{
	bool temp = false;
	switch (e)
	{
	case '+':
	case '-':
	case '*':
	case '/':
	case '(':
	case ')':
	case '%':
		temp = true;
		break;
	default:
		break;
	}
	return temp;
}
int levelSymbol(const char c1)
{
	int i = 0;
	if (c1 == '+' || c1 == '-')
	{
		i = 1;
	}
	if (c1 == '*' || c1 == '/' || c1 == '%')
	{
		i = 2;
	}
	return i;
}
bool checkLevel(const char c1, const char c2)
{
	return levelSymbol(c1) <= levelSymbol(c2);
}


string reverseConvert(const string& inputString)
{
	ChainStack<char> tempStack;
	string temp, returnString;
	char topChar;
	
	temp = inputString;
	string::iterator i = temp.begin();
	for (; i != temp.end(); ++i)//从左至右扫描中缀表达式
	{
		tempStack.GetTop(topChar);
		if (isNumber(*i))
		{
			returnString += *i;
		}
		else
		{
			if (isSymbol(*i))//若读取的是运算符
			{
				if (*i == '(')//该运算符为左括号"(",则直接存入运算符堆栈。
				{
					tempStack.Push(*i);
				}
				else{
						if (*i == ')')//该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。
							{
								while (topChar != '(')
									{
										tempStack.Pop(topChar);
										returnString += topChar;
										tempStack.GetTop(topChar);//运算完后重新获取栈顶元素
									}
								tempStack.Pop(topChar);//把topChar='('弹出栈
							}
						else
							{
								tempStack.GetTop(topChar);
								if (topChar == '(' || tempStack.Empty())//若运算符堆栈栈顶的运算符为左括号或者为空栈,则直接存入运算符堆栈。
										{
											tempStack.Push(*i);
										}
										//若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈
								else{
											while (checkLevel(*i, topChar))//如果当前符合*i比栈顶符号topChar的运算级低或者相等
											{
												tempStack.Pop(topChar);//将栈顶元素弹出赋给输出串,直到栈顶符合的运算级小于等于当前符号
												returnString += topChar;
												if(!tempStack.GetTop(topChar)) break;//如果栈为空跳出循环
												//tempStack.Push(*i);
											}
											tempStack.Push(*i);//把当前符号压入栈中
									}
							}
					}
			}
		}
	}
	while (!tempStack.Empty())
	{
		tempStack.Pop(topChar);
		returnString += topChar;
	}

	return returnString;
}

上述算法有一个缺点:不能计算大于九的数,因为大于九,其数字用字符表示为两个或者更多个字符,在操作的时候有所不同。可以在下次复习使用string的时候写出。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!