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

逆波兰表示法(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的时候写出。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-06 07:10:40

C++的逆波兰表达式的求解的相关文章

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

#include <iostream> using namespace std; #include <stack> #include <assert.h> enum Type { OP_SYMBOL, OP_NUM, ADD, SUB, MUL, DIV, }; struct Cell { Type _type; int _value; }; int CountRPN(Cell a[], size_t size) { assert(a != NULL); stack&l

栈的应用---逆波兰表达式

学习了栈后,那么栈有什么用呢?下面就举一个经典的例题---逆波兰表达式的求解. 首先呢,什么是逆波兰表达式呢? 逆波兰表达式呢,就是先是操作数,后操作符. 所有的表达式都可以写成逆波兰表示式的形式. 假如现有一逆波兰表达式,那么如何求它的解呢?我们的栈就要派上用场喽! 思路: 如果遇到操作数,就将其放入栈中,如果遇到操作符,则取出两个操作数进行运算.将其结果压入栈中.直到遇到最后一个操作符运算后压入栈中,出栈即为表达式的结果. 逆波兰表达式有两种类型:操作数,操作符. 可将逆波兰表达式看成一个C

求解逆波兰表达式的值

题目: Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, *, /. Each operand may be an integer or another expression. Some examples:   ["2", "1", "+", "3", "*"

求解逆波兰表达式(前缀表达式)

首先介绍一下逆波兰表达式 逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3.逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的逆波兰表示法为* + 2 3 4. 这个表达式的求法有很多种 这里介绍一种用递归求解的方法.. 时间复杂度O(n); 首先我们需要把表达式转换成运算符和数字. 用一个数组记录i位置是数字还是运算符. 如果是数字是浮点数的话可使用atof(str)把字符串转换为一个doubl

逆波兰表达式

1696:逆波兰表达式 总时间限制: 1000ms 内存限制: 65536kB 描述 逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3.逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的逆波兰表示法为* + 2 3 4.本题求解逆波兰表达式的值,其中运算符包括+ - * /四个. 输入 输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数. 输出 输出为一行,表达式的值.可直接用prin

逆波兰表达式(栈,递归)

1696:逆波兰表达式 总时间限制:  1000ms 内存限制:  65536kB 描述 逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3.逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的逆波兰表示法为* + 2 3 4.本题求解逆波兰表达式的值,其中运算符包括+ - * /四个. 输入 输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数. 输出 输出为一行,表达式的值.可直接用pr

逆波兰表达式的实现

一般情况下表达式是由操作数和运算符组成,例如算数表达式中通常将运算符放在两个操作数中间,譬如a+b的形式,这种形式称为中缀表达式,那么问题来了,是否有后缀表达,前缀表达式呢??? 对,没错,这些后缀表达,前缀表达式都是由波兰数学家Jan Lukasiewicz提出来的 把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB: 把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expressio

逆波兰表达式 (递归+结构体函数)

标题:逆波兰表达式 正常的表达式称为中缀表达式,运算符在中间,主要是给人阅读的,机器求解并不方便. 例如:3 + 5 * (2 + 6) - 1 而且,常常需要用括号来改变运算次序. 相反,如果使用逆波兰表达式(前缀表达式)表示,上面的算式则表示为: - + 3 * 5 + 2 6 1 不再需要括号,机器可以用递归的方法很方便地求解. 为了简便,我们假设: 1. 只有 + - * 三种运算符 2. 每个运算数都是一个小于10的非负整数 下面的程序对一个逆波兰表示串进行求值. 其返回值为一个结构:

noi1696 逆波兰表达式

1696:逆波兰表达式 http://noi.openjudge.cn/ch0303/1696/ 总时间限制:  1000ms 内存限制:  65536kB 描述 逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3.逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的逆波兰表示法为* + 2 3 4.本题求解逆波兰表达式的值,其中运算符包括+ - * /四个. 输入 输入为一行,其中运算符和运算数之间