中缀表达式转后缀表达式(逆波兰式)并且计算结果

之前学习编译原理时写过类似的代码,当时的思路不是特别好,后来看《算法笔记》又遇到了这一题,按照书上的原理自己用C++模拟实现了一遍,因此记录一下思路和代码。
思路:
(1)中缀表达式转后缀表达式

设一个运算符栈,用来临时存放操作符,一个队列,用来存放生成的后缀表达式。

  • 从左向右扫描中缀表达式,如果遇到操作数num:直接添加num到后缀表达式队列中。
    如果遇到的是运算符op1:如果该运算符op1比栈顶运算符优先级高,则把该操作符op1入栈。否则把栈顶的运算符弹出加入到后缀表达式队列中,直到当前栈顶的元素优先级小于op1,此时,再把op1入栈。
    如果遇到的是’(‘或’)’:
    对于’(’,则直接入栈,并且标记’(‘的优先级为最小。
    对于’)’,则一直弹出栈并且加入到后缀表达式中,直到把’)'也弹出。
    ‘(’和‘)’s是不需要加入到后缀表达式中的
  • 在上述过程扫描完毕后,栈中可能非空,此时需要把栈中所有元素依次pop,加入到后缀表达式队列中。

例如,中缀表达式1*(2+3/(4+5))对应的后缀表达式为12345+/+*

(2)计算后缀表达式

计算后缀表达式的过程较为简单,需要一个栈来临时存储中间结果和运算符。

  • 从左向右扫描中缀表达式(即上述步骤一得到的队列)
  • 如果是操作数,直接压入栈中,如果是运算符op2,则从栈中弹出两个元素,先弹出的是第二个操作数num2,后弹出的是第一个操作数num1,在计算num1 op2 num2的结果,将结果压入栈中。
  • 扫描完毕后,栈中剩下的一个元素即为计算结果。

c++代码

注意的是,因为涉及的除法,因此可能产生小数,因此使用double。输入时直接用字符串string接受,因此要一边扫描字符串一边简单处理。

#include
#include
#include
#include
#include 	
using namespace std;

struct node{
	double num;	//操作数 
	char op;	//运算符 
	bool flag;	//ture表示操作数,false表示运算符 
};

string s;	//中缀表达式 
stack opstack;	//运算符栈
queue rpqueue;	//逆波兰表达式 
map op;	//运算符优先级
 
void to_reverse_polish(string s){	//转逆波兰(中缀)表达式
	int len = s.size();
	node t;	//t记录当前节点的数字或者操作符 
	for(int i = 0 ;i='0'){
			t.num = 0;
			t.flag = true;
			t.num += s[i++]-'0';	//取操作数
			while(i='0'){
				t.num = t.num*10+s[i++]-'0';
				i++;
			}
			rpqueue.push(t);
		}
		else{
			t.flag = false;		//取运算符
			t.op = s[i];
			if(s[i]=='('){
				opstack.push(t);
				i++;
				continue;
			}
			if(s[i]==')'){
				while(opstack.top().op!='('){
					rpqueue.push(opstack.top());
					opstack.pop();
				}
				opstack.pop();	//把左括号消掉
				i++;
				continue; 
			}
			while(!opstack.empty()&&op[s[i]]<=op[opstack.top().op]){	//当前栈非空,栈顶运算符优先级较大 
				rpqueue.push(opstack.top());
				opstack.pop();
			}
			opstack.push(t);
			i++;
	}
			}
		while(!opstack.empty()){
			rpqueue.push(opstack.top());
			opstack.pop();
		}
}

double cal_rp(){	//计算逆波兰表达式的值 
	stack cal_stack;
	node t;
	double num1,num2;
	while(!rpqueue.empty()){	 
		if(rpqueue.front().flag){
			cal_stack.push(rpqueue.front());
			rpqueue.pop();
		}
		else{
			if(rpqueue.front().op=='+'){
				num2 = cal_stack.top().num;
				cal_stack.pop();
				num1 = cal_stack.top().num;
				cal_stack.pop();
				t.flag = true;
				t.num = num1+num2;
				cal_stack.push(t);
			}else if(rpqueue.front().op=='-'){
				num2 = cal_stack.top().num;
				cal_stack.pop();
				num1 = cal_stack.top().num;
				cal_stack.pop();
				t.flag = true;
				t.num = num1-num2;
				cal_stack.push(t);
			}else if(rpqueue.front().op=='*'){
				num2 = cal_stack.top().num;
				cal_stack.pop();
				num1 = cal_stack.top().num;
				cal_stack.pop();
				t.flag = true;
				t.num = num1*num2;
				cal_stack.push(t);
			}else if(rpqueue.front().op=='/'){
				num2 = cal_stack.top().num;
				cal_stack.pop();
				num1 = cal_stack.top().num;
				cal_stack.pop();
				t.flag = true;
				t.num = num1/num2;
				cal_stack.push(t);
			}
			rpqueue.pop();
		}
	}
	return cal_stack.top().num;
}

int main(){
	op['+'] = 1;
	op['-'] = 1;
	op['*'] = 2;
	op['/'] = 2;
	op['('] = 0;
	cin>>s;	//输入表达式 
	to_reverse_polish(s);	//转逆波兰表达式存在队列rpqueue中 
	queue print_queue = rpqueue;
	while(!print_queue.empty()){	//输出逆波兰表达式 
		if(print_queue.front().flag == true)
			cout<

你可能感兴趣的:(算法,C++)