逆波兰表达式转换与求值

本文详细介绍了逆波兰表达式的概念、转换过程(使用栈操作符和括号),以及如何通过栈结构计算逆波兰表达式的值,包括运算符优先级的处理方法。
摘要由CSDN通过智能技术生成

1.关于概念

逆波兰表达式又叫做后缀表达式。逆波兰表示法是波兰逻辑学家J・卢卡西维兹于1929年首先提出的一种表达式的表示方法 。后来,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。

1 + 2为例
中缀表达式:1+2。 顾名思义,运算符在中间。
前缀表达式:+12。又称波兰表达式,运算符在操作数的前面
后缀表达式:12+。 又称逆波兰表达式。运算符在中间。

对于一个数学表达式,将其转换成后缀表达表达式的过程如下:
在这里插入图片描述

2.关于转换

对于给定的表达式,可以根据下面的算法进行求解。

  • 1.建立两个栈A,B,A栈用来存放字符串中的左括号以及运算符,B栈用以存放结果。
  • 2.遍历字符串,对遍历到的每个元素进行如下规则的判断。
  • 3.如果遇到左括号,直接压入A栈。
  • 4.如果遇到数字,直接压入B栈。
  • 5.如果遇到运算符,需要进行判断。
    5.1 如果A栈顶元素为左括号或A栈为空,直接压入A栈。
    5.2 如果A栈顶元素优先级小于自身,直接压入A栈。
    5.3 如果A栈顶元素优先级大于自身,需要将A栈顶的元素重复移至B栈,直至A栈顶元素优先级不大于自身,最后再压入A栈。
  • 6.如果遇到有括号,重复将A栈顶元素移入B栈,直到遇到左括号,最后弹出左括号。

当遍历完整个字符串后,最后将A栈中元素顺序移入B栈,最后发现B栈从栈低至栈顶就是要求解的答案,只需将B栈方向输入即可。

对于如何比较运算符优先级,可以定义一个函数来实现,不同优先级的运算符芳会不同大小的数。

int priorityComparison(char a){
	if(a == '*' || a == '/'){
		return 2;
	}else{
		return 1;
	}
}

优先级最高的乘除返回2,其余返回1.

转换函数:

void getPolandNums(char *arr,int len){
	for(int i=0;i<len;i++){ //遍历字符数组
		if(arr[i] == '('){  //1.如果是左括号,压入A
			A.push(arr[i]);
		}
		else if(arr[i]>='0' && arr[i]<='9'){ //2.如果是数字,压入B
			B.push(arr[i]);
		}
		//3.如果是运算符
		else if(arr[i]=='+'||arr[i]=='-'||arr[i]=='*'||arr[i]=='/'){
			if(A.empty() || A.top() == '('){  //3.1 如果A栈为空或栈顶元素为左括号,压入A
				A.push(arr[i]);
			}
			else if(priorityComparison(A.top()) <= priorityComparison(arr[i])) { //3.2栈顶元素优先级 小于 自身,也压入A
				A.push(arr[i]);
			}
			//3.3栈顶元素优先级 大于 自身,重复把A栈顶的元素移到B,直到A栈顶的优先级不大于自己
			else if(priorityComparison(A.top()) > priorityComparison(arr[i])){
				while(priorityComparison(A.top()) > priorityComparison(arr[i])){ //重复把优先级高的移走
					B.push(A.top());
					A.pop();
				}
				A.push(arr[i]); //移走之后就可以放进来
			}
		}
		//4.如果是右括号
		else if(arr[i] == ')'){
			while(A.top() != '('){ //把A的元素重复移到B中,直到A栈顶为左括号
				B.push(A.top());
				A.pop();
			}
			A.pop();//把栈顶的左括号删除
		}
	}
	//把A剩余的拼接到B
	while (A.size()) {
		B.push(A.top());
		A.pop();
	}
	//5.把B中的元素移到C(交换顺序)
	stack<char> C;
	while(B.size()){  
		C.push(B.top());
		B.pop();
	}
	//输出C
	while(C.size()){  
		cout<<C.top();
		C.pop();
	}
}

3.关于求值

通过上面的函数,可以拿到一个经过转换后的逆波兰表达式,例如1 2 + 3 4 - *,它的原表达式为(1+2)*(3-4),那么该表达式的值为-3.

要求逆波兰表达式的值,可以遵循以下算法步骤。

  • 1.建立一个两个栈AB,一个用来存放数字,一个用来存放运算符。
  • 2.遍历字符串,对遍历到的每个元素进行如下规则的判断。
  • 3.如果是数字,压入A栈。
  • 4.如果是运算符,首先弹出A栈顶元素n1,在弹出新的栈顶元素n2,之后将n1 n2根据运算符执行相应的运算,最后将得到的数据再压入A栈。

当遍历完成,最后A栈只剩一个元素,即要求解的答案。

完整函数如下(保证给定的逆波兰表达式是合法的)

int getsAns(char *arr,int len){
	for(int i = 0; i < len; i ++){
		if (arr[i] >= '0' && arr[i] <= '9'){
			A.push(int(arr[i]-48));
		}
		else if(arr[i]=='+'||arr[i]=='-'||arr[i]=='*'||arr[i]=='/'){
			int n1 = A.top();
			A.pop();
			int n2 = A.top();
			A.pop();
			switch (arr[i]) {
				case '+':
					A.push(n2 + n1); break;
				case '-':
					A.push(n2 - n1); break;
				case '*':
					A.push(n2 * n1); break;
				case '/':
					A.push(n2 / n1); break;
			}
		}
	}
	return A.top();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值