Expression Trees and Reverse Polish Expressions

The theoretical concept part:       

         In the field of computer applications, the order of calculation is limited by the priority and associativity of operators, and the order of calculation can be changed by adding parentheses, which makes the process of calculating the value of an expression more complicated. Here are a few ways to find the value of an expression.
        The common way of expressing expressions is that the operator (binary operator) is placed in the middle of the operands. This way of expressing expressions is called infix expression . For example, in the mixed arithmetic formula 46/2+32x(5-17), the two operands 46 and 2 of the division sign are placed on both sides of the division sign, and the two operands of the addition sign 46/2 and 32x(5 -17) placed on both sides of the plus sign. to humans

 

 Complete code implementation:

#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);
}

Guess you like

Origin blog.csdn.net/qq_62687015/article/details/128710636