数据结构——表达式求值

1.介绍

表达式分为中缀表达式,后缀表达式和前缀表达式。

前缀表达式又叫波兰式,而后缀表达式又叫逆波兰式,因为一开始研究这个的是个波兰数学家。

其中,我们最熟悉的就是中缀表达式。如下:

(15-2)*3+4/2

表达式分为三个部分,操作数运算符界限符

操作数就是上面的数字,运算符就是加减乘除一类的运算符号,界限符就是我们熟悉的大括号、中括号和小括号。

实际上,界限符是决定运算顺序的符号。

对于五加三,三种表达式有三种不同的表达方式,而结果其实并没有变化。

中缀表达式就是运算符号置于两个操作数之间,如5+3。

后缀表达式就是将运算符置于两个操作数之后,如 5 3+。

那么前缀表达式就是将运算符置于两个操作数之前,如 +5 3。

注意:这里数字的顺序是不能改变的,尤其对于-*/这三种运算符,这和5-3跟3-5不同是一样的道理。

对于上面的5相同的地位的数称为前操作数,对于上面的3相同的地位的数称为后操作数。

2.操作

我们知道一个表达式最终目的是化为一个操作数,因此,我们就可以在复合表达式中,将某个部分表达式视为一个操作数。

比如说(15-2)*3+4/2,我们就可以将(15-2)*3当成一个操作数去对待,而不用管表达式里面如何如何复杂。

(1)将中缀表达式转换为后缀表达式

 举个例子:

(15-2)*3+4/2将这个中缀表示式化为后缀表达式。

我们先确定运算的顺序,如下:

数据结构——表达式求值_第1张图片

 第一步:15 2 -,我们将这个部分表达式视为一个操作数,进行下一步。

第二步: 15 2 - 3 *,操作数顺序不能颠倒

第三步: 15 2 - 3 * 4 2 /,这里又增加了一个‘操作数’,进行下一步。

第四步: 15 2 - 3 * 4 2 / +,最终的到的式子就是后缀表达式。

其实,有的中缀表达式,不止一个运算顺序,因此,也就有不同的后缀表达式相对应。

如:15/5*3+5-2

我们既可以先算乘法,再算除法,也可以先算除法,再算乘法。

在乘除运算之后,我们既可以先算加法,也可以先算减法。

对于算法来说,算法具有确定性,因此计算机一般转换时都是按‘左优先’算法转换的,即假如运算符的优先级相同,比如*和/这两种运算符,则先从左边开始转化

也就是说能先从左边开始,就从左边开始。

这样求得的后缀表达式就是唯一的,也可以看到上面我们求后缀表达式的式子,原本的运算顺序为1243,转换为后缀biao'da'shi后为1234。

上面都是手算,下面来看代码:

数据结构——表达式求值_第2张图片

代码在最后。

(2)后缀表达式的计算 

对于上面我们求出的算数表达式,如果我们想要计算,我们观察这个式子,很快就能相处计算方法。

方法如下:

数据结构——表达式求值_第3张图片

比如说:上面我们求后缀表达式的中缀表达式式子为(15-2)*3+4/2,经计算为41。

后缀表达式为15 2 - 3 * 4 2 / +

我们采用后缀表达式的计算方法计算一遍。

第一次遇到运算符为‘-’,那么得到15-2=13。

第二次遇到运算符为‘*’,那么得到13*3=39。

第三次遇到运算符为‘/’,那么得到4/2=2。

第四次遇到运算符为‘+’,那么得到39+2=41。

完全和中缀表达式计算得到的结果相同。上面的方法对于哪一种后缀表达式都是适用的。

有了这种思想其实前缀表达式,同样的自己也就可以解决了。

(3)将中缀表达式转换为前缀表达式

数据结构——表达式求值_第4张图片

举个例子:

(15-2)*3+4/2将这个中缀表示式化为前缀表达式。

我们先确定运算的顺序,如下:

数据结构——表达式求值_第5张图片

 第一步:/ 4 2,这里的表达式又是一个操作数。

第二步:- 15 2 / 4 2,操作数顺序不能颠倒

第三步:* - 15 2 3 / 4 2

第四步:+ * - 15 2 3 / 4 2,最终的到的式子就是前缀表达式。

同理,算法具有确定性,因此,规定‘右优先‘,最后将运算的顺序2341转化后为4321。

操作3和4可以自己试着模仿1和2写代码,因此就不给代码了。

(4)前缀表达式的计算 

对于上面我们求出的算数表达式,如果我们想要计算,我们观察这个式子,很快就能相处计算方法。

它和后缀表达式的计算方法顺序相反,如下:

举个例子: 计算上面求得的前缀表达式+ * - 15 2 3 / 4 2

 从右向左:

第一次遇到运算符’/‘,得到4/2=2。

第二次遇到运算符’-‘,得到15-2=13

第三次遇到运算符’*‘,得到13*3=39

第四次遇到运算符’+‘,得到39+2=41

因此,41就是该前缀表达式的值。

(5)中缀表达式的计算

其实,对于中缀表达式,人是非常好计算的。但对于计算机而言,中缀表达式的计算方法是非常复杂的。

这就需要先将中缀转前缀或者后缀,然后按转换后的表达式的计算方法计算。

代码在最后。

//expression.h
#pragma once
#include
#include
class expression
{
public:
	std::string inExpression;//中缀表达式
	std::string poExpression;//后缀表达式
	std::string prExpression;//前缀表达式

	expression(std::string obj);
	~expression(){};
	int priority(char op);//运算符的优先级
	bool isOp(char op);//是否是四种运算符号
	std::string readInNum(int &i);//读取中缀表达式中数字
	std::string readPoNum(int &i);//读取后缀表达式中数字
	void inToPo();//中缀转后缀
	void inToPr();//中缀转前缀
	int answer();//表达式结果
	
};

//expression.cpp
#include "expression.h"
expression::expression(std::string obj)
{
	inExpression = obj;
}
bool expression::isOp(char op)
{
	if (op == '+' || op == '-' || op == '*' || op == '/')
		return true;
	return false;
}
int expression::priority(char op)
{
	switch (op)
	{
		case '+':
		case '-':return 0;
		case '*':
		case '/':return 1;
		default:
			break;
	}
	return -1;
}
std::string expression::readInNum(int &i)
{
	std::string num;
	while (isdigit(inExpression[i]))
	{
		num += inExpression[i];
		i++;
	}
	i--;
	return num;
}
std::string expression::readPoNum(int& i)
{
	std::string num;
	while (isdigit(poExpression[i]))
	{
		num += poExpression[i];
		i++;
	}
	i--;
	return num;
}
void expression::inToPo()
{
	//(15-2)*3+4/2
	//h
	//po
	std::stack h;
	for (int i = 0; i < inExpression.size(); i++)
	{
		if (isdigit(inExpression[i]))
		{
			poExpression += readInNum(i);
			poExpression += ' ';
		}
		else if (inExpression[i] == '(')
			h.push(inExpression[i]);
		else if (inExpression[i] == ')')
		{
			while (h.top() != '(')
			{
				poExpression += h.top();
				poExpression += ' ';
				h.pop();
			}
			h.pop();
		}
		else if (isOp(inExpression[i]))
		{
			//因为栈顶一定是优先级最高的,每次只需要和栈顶元素比较就行
			while (!h.empty() && priority(inExpression[i]) < priority(h.top()))
			{
				poExpression += h.top();
				poExpression += ' ';
				h.pop();
			}
			h.push(inExpression[i]);
		}
	}
	while (!h.empty())
	{
		poExpression += h.top();
		poExpression += ' ';
		h.pop();
	}
}
void expression::inToPr()
{

}
int cal(int lhs, int rhs,char op)
{
	switch (op)
	{
	case '+':return lhs + rhs;
	case '-':return lhs - rhs;
	case '*':return lhs * rhs;
	case '/':return lhs / rhs;
	default:
		break;
	}
	return 0;
}
int expression::answer()
{
	std::stacknum;
	for (int i = 0; i < poExpression.size(); i++)
	{
		if (isdigit(poExpression[i]))
			num.push(std::stoi(readPoNum(i)));
		else if (poExpression[i] == ' ')
			continue;
		else if (isOp(poExpression[i]))
		{
			int rhs = num.top();
			num.pop();
			int lhs = num.top();
			num.pop();
			num.push(cal(lhs, rhs, poExpression[i]));
		}
	}
	return num.top();
}

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