表达式树和逆波兰表达式

理论概念部分:       

         在计算机应用领域,由于运算符的优先级和结合性不同限定了计算的顺序,另外通过加括号可以改变计算顺序,使得求一个表达式的值的过程变得比较复杂。下面介绍几种求表达式值的方法。
        常见的表达式表示方式是操作符(双目运算符)放在操作数的中间,这类表示表达式的方式称为中缀表达式。例如,四则混合运算式 46/2+32x(5- 17)中,除号的两个操作数46和2放置在除号的两侧,加号的两个操作数 46/2 和 32x(5-17)放置在加号的两侧。对人类

 

 完整代码实现:

#include<iostream>
#include<map>
#include<stack>
using namespace std;
constexpr auto N = 30;

//逆波兰表达式中元素的表示方法
/*
	其中,需要预先为每一个运算符指定优先级,存放在pri中,
	另外,为了节省空间,定义一个共用体data存放操作数和运算符,
	tag用于区分当前元素为操作数还是运算符。
*/
map<char,int>pri; //优先级
typedef struct rpn_node {
	bool tag; //true:元素为操作数;false:元素为运算符
	union {
		int v; //操作数
		char op; //运算符
	}data;
}rpn[N];

//调度场算法
//定义所涉及的运算符的优先级,可根据c++中运算符的优先级表
void Init() {
	pri['+'] =  6 ;
	pri['-'] =  6 ;
	pri['*'] =  5 ;
	pri['/'] =  5 ;
	pri['('] =  99 ;
	pri[')'] =  99 ;
	pri['$'] =  99 ;
}
//将中缀表达式infix转化为逆波兰表达式,结果存放在posfix中,n为逆波兰表达式中元素的个数
void shuntingYard(string infix, rpn& posfix, int& n) {
	infix += '$', n = 0;//为infix加一个后缀
	int i = 0, len = infix.length(), num = 0;
	stack<char>stk;
	for (i = 0; i < len; i++) {
		if (isdigit(infix[i])) { //当前字符为数字
			num = 0;
			while (isdigit(infix[i])) //获取连续的数字所表示的数
				num = num * 10 + infix[i++] - '0';
			posfix[n].tag = true;//将数字加入逆波兰表达式
			posfix[n++].data.v = num;
			i--;
		}
		else { //当前字符为运算符
			if (infix[i] == '(') {   //( 直接入栈
				stk.push(infix[i]);
				continue;
			}
			while (!stk.empty() && pri[stk.top()] <= pri[infix[i]]) {//当前运算符与栈顶运算符进行优先级比较
				if (stk.top() == '(') { //如果栈顶元素为'(',退出循环
					if (infix[i] == ')') stk.pop(); //如果当前元素为')','('出栈
					break;
				}
				posfix[n].tag = false; //将栈顶元素加入逆波兰表达式
				posfix[n++].data.op = stk.top();
				stk.pop();
			}
			if (infix[i] != ')') stk.push(infix[i]);//当前字符入栈,)除外,其让栈顶元素出栈
		}
	}
}

//利用表达式的逆波兰表达式求表达式的值
//返回表达式v1 op v2 的计算结果
double cal(double v1, char op, double v2) {
	switch(op){
		case '+':return v1 + v2;
		case '-':return v1 - v2;
		case '*':return v1 * v2;
		case '/':return 1.0 * v1 / v2;
	}
}
//计算具有n项的逆波兰表达式posfix表达式的值,结果作为返回值
double calculate(rpn posfix, int n) {
	double v1, v2;
	stack<double>stk;
	for (int i = 0; i < n; i++) {
		if (posfix[i].tag) //当前项为操作数,直接入栈
			stk.push(posfix[i].data.v);
		else { //当前项为运算符,从栈中取两项
			v1 = stk.top(), stk.pop();
			v2 = stk.top(), stk.pop();
			stk.push(cal(v2, posfix[i].data.op, v1)); //计算并将计算结果入栈
		}
	}
	return stk.top(); //最后栈顶元素即为表达式的值
}
	
int main() {
	Init();
	string infix = "46/2+32*(5-17)";
	rpn r1; //学会创建结构体数组的变量
	int number;
	shuntingYard(infix, r1, number);
	/*for (int i = 0; i < 9; i++) {
		cout << r1[i].data.v << " " << r1[i].data.op << endl;
	}*/
	cout << calculate(r1, number);
}

猜你喜欢

转载自blog.csdn.net/qq_62687015/article/details/128710636